사자자리
[React] Immutable 본문
배열: push와 concat
arr.push()
- arr을 바꾼다.
arr.concat()
- arr을 바꾸지 않는다.
- arr을 변경한 새로운 배열이 return된다.
push 대신 concat을 권장하는 이유
컴포넌트의 render 호출을 control하기
1. TOC 컴포넌트의 역할은 글 목록이다. TOC 컴포넌트가 화면에 표시되기 위해 필요한 데이터는 contents 배열이다.
contents:[
{id:1, title:'HTML', desc:"HTML is for information"},
{id:2, title:'CSS', desc:"CSS is for design"},
{id:3, title:'JS', desc:"JS is for interfactive"}
]
2. 위의 contents 배열의 내용이 바뀌었다면, TOC 컴포넌트의 render의 호출을 통해 TOC가 다시 그려지는 것이 맞다.
3. 그러나, contents 배열의 내용이 바뀌지 않았다면, TOC 컴포넌트의 render는 호출되는 것이 좋지 않다.
4. TOC 컴포넌트의 render 메소드에 console.log('TOC render');를 입력하고 다른 목록을 클릭하면, contents 배열의 내용이 바뀌지 않았음에도 TOC가 렌더링이 되는 것을 알 수 있다.
//TOC.js
import React, {Component} from 'react';
class TOC extends Component{
render(){
console.log('TOC render');
(생략)
- 처음 한 번은 웹페이지가 그려져야 하기 때문에 렌더링된다.
- 다른 목록(HTML, CSS, JS)를 클릭했을 때, contents의 내용에는 변경이 없지만 TOC는 렌더링된다.
- 이는 큰 프로그램을 작성할 때, 중요한 이슈가 된다.
5. shouldComponentUpdate 함수: 성능을 향상시키기 위해, 컴포넌트의 render 함수가 실행될지 실행되지 않을지를 결정할 수 있도록 하는 함수
- return true: render 함수가 호출된다.
- return false: render 함수가 호출되지 않는다.
- 부모 컴포넌트의 state 값이 바뀌면 자식 컴포넌트들을 모두 다시 렌더링되는데, 이 렌더링도 막을 수 있다.
6. shouldComponentUpdate 함수는 2개의 매개변수를 가진다.
- newProps: 컴포넌트의 props가 바뀌었을 때, 바뀐 props의 값
- newState: 컴포넌트의 state가 바뀌었을 때, 바뀐 state의 값
//TOC.js
import React, {Component} from 'react';
class TOC extends Component{
shouldComponentUpdate(newProps, newState){
console.log(
'TOC render shouldComponentUpdate',
newProps.data, //바뀐 props값
this.props.data //바뀌기 전의 props값
);
return false; //render가 호출되지 않는다.
}
render(){
console.log('TOC render');
(생략)
- newProps.data는 원소가 4개인 배열, this.props.data는 원소가 3개인 배열이다.
- 따라서, shouldComponentUpdate는 새롭게 바뀐 값고 이전 값에 접근할 수 있다.
7. 이를 통해, TOC로 들어오는 props의 값이 바뀌었을 때는 render가 호출되고, props의 값이 바뀌지 않았을 때는 render가 호출되지 않게 할 수 있다.
//TOC.js
import React, {Component} from 'react';
class TOC extends Component{
shouldComponentUpdate(newProps, newState){ //TOC 컴포넌트의 props와 state가 바뀌었을 때 바뀐 값이 들어온다.
console.log(
'TOC render shouldComponentUpdate',
newProps.data, //바뀐 props값
this.props.data //바뀌기 전의 props값
);
if (this.props.data === newProps.data){ //props의 값이 같다면, 바뀐 것이 없으므로
return false; //render를 호출하지 않는다.
}
return true; //if 조건문에 해당하지 않는다면, props의 값이 바뀌었으므로 render를 호출한다.
}
render(){
console.log('TOC render');
(생략)
응용하기
1. push
//App.js
else if(this.state.mode === "create"){
_article = <CreateContent onSubmit={function(_title, _desc){
this.max_content_id += 1;
this.state.contents.push(
{id: this.max_content_id, title: _title, desc: _desc}
);
this.setState({contents: this.state.contents});
}.bind(this)}></CreateContent>
}
- this.state.contents의 원본을 바꿔서 this.props.data와 newProps.data의 값이 완전히 같다.
- contents 배열의 내용이 바뀌었음에도 render가 호출되지 않아서 React(push)가 추가된 내용이 화면에 반영되지 않는다.
2. concat
//App.js
else if(this.state.mode === "create"){
_article = <CreateContent onSubmit={function(_title, _desc){
this.max_content_id += 1;
var _contents = this.state.contents.concat(
{id: this.max_content_id, title: _title, desc: _desc}
);
this.setState({contents: _contents});
}.bind(this)}></CreateContent>
}
- 원본을 수정하지 않아서 this.props.data와 newProps.data의 값이 다르다.
- TOC의 render가 호출된다.
3. 배열일 때: push와 Array.from
Array.from()
- 원본을 건들지 않고 복제한다.
//App.js
else if(this.state.mode === "create"){
_article = <CreateContent onSubmit={function(_title, _desc){
this.max_content_id += 1;
var newContents = Array.from(this.state.contents);
newContents.push({id: this.max_content_id, title: _title, desc: _desc})
this.setState({contents: newContents});
}.bind(this)}></CreateContent>
}
- Array.from으로 원본 배열을 복사해서 push를 사용했기 때문에, 원본을 변경하지 않았다.
4. 객체일 때: Object.assign( , )
- 배열일 때와 같은 맥락으로, 객체일 때는 Object.assign을 사용해서 원본은 immutable하게 두고 복제할 수 있다.
'웹기초 > 생활코딩 REACT' 카테고리의 다른 글
[React] delete 구현 (0) | 2022.08.03 |
---|---|
[React] Update 구현 (0) | 2022.07.27 |
[React] Create 구현 (0) | 2022.07.27 |
[React] 컴포넌트 이벤트 만들기 (0) | 2022.07.20 |
[React] props, state, bind, 이벤트 (0) | 2022.07.20 |