props와 state의 차이점

props는 read-only이지만 state는 setState를 통해서 수정이 가능하다.
예를 들어, 현재 Content라는 컴포넌트를 사용하는 APP.js 에서는 title이라는 props를 통해 값을 주입할 수 있다.

하지만 Content 내부에서 title 값을 hi로 바꾸려고 하면 에러가 발생하게 된다.

이렇게 컴포넌트 안에서 자신에게 전달된 props 값을 바꾸는 것은 금지되어있다!
컴포넌트 밖에서만 props를 바꾸는 것이 허용되기 때문에 props가 수정할 수 없는 read-only라는 것!
props와 이벤트

위에 있는 동그라미는 상위 컴포넌트, 아래 동그라미는 하위 컴포넌트이다.
지금까지 만든 컴포넌트로 따지면 상위 컴포넌트는 App.js, 하위 컴포넌트는 Content, Subject, TOC 가 해당된다.
이러한 상위 컴포넌트가 하위 컴포넌트로 값을 전달할 땐 props를 통해 전달하고,
하위 컴포넌트가 상위 컴포넌트의 값을 바꾸고 싶을 땐 이벤트를 통해 값을 변경한다.
상위 컴포넌트 App.js 에서 하위 컴포넌트 TOC로 값을 전달할 땐 data라는 props를 통해서 전달한다.

하지만 하위 컴포넌트 TOC에서 글 목록을 클릭했을 때 APP.js 컴포넌트의 state와 selected_content_id를 바꾸고자 한다면 onChangePage와 같은 이벤트로 상위 컴포넌트의 state 값을 호출하여 state 값을 바꿀 수 있다.
이렇게 지금까지 만든 애플리케이션은 read만 가능하다. 그래서 이제 데이터를 동적으로 추가하고, 수정하고, 삭제하는 방법을 알아보자!
앞으로 배워야 할 것은 CRUD이다.
Create Read Update Delete
이것을 알면 다 아는 것!
create
목표:
글 목록 밑에(TOC와 Content 사이) 생성, 수정, 삭제 버튼을 만든다.
생성 버튼을 누르면 APP의 mode가 create로 바뀌고 Content 컴포넌트가 글을 추가할 수 있는 컴포넌트로 바뀔 것이다.
글을 추가하면 APP 컴포넌트 state의 contents에 글과 id값과 제목 정보가 담긴 객체가 추가될 것이다.
그러면 이렇게 추가된 글에 따라 TOC에 표시될 내용이 달라진다.
글 목록과 content 사이에 create, update, delete 버튼을 만들기
이 버튼들은 Control이라는 컴포넌트 안에 넣어줄 것이다.
import React, { Component } from 'react';
class Control extends Component{
render(){
return (
<ul>
<li><a href='/create'>create</a></li>
<li><a href='/update'>update</a></li>
<li><input type="button" value='delete'></input></li>
</ul>
);
}
}
export default Control;
delete 버튼만 a태그가 아닌 input 태그인 이유는 만약 사용자가 웹페이지에 방문했을 때 링크에 더 빠르게 접속할 수 있도록 링크가 미리 실행되는 기능을 사용한다면? delete 가 사용돼버리면 내용이 삭제되어버린다. 이러한 상황을 막기 위해 delete는 input 태그를 사용한다.
이제 Control 컴포넌트 안에 있는 버튼을 클릭하면 그에 따라 모드가 바뀌는 이벤트가 발생하도록 하기 위해 이벤트를 설정해보자.
//Control.js
<ul>
<li><a href='/create' onClick={function(e){
e.preventDefault();
this.props.onChangeMode('create');
}.bind(this)}>create</a></li>
<li><a href='/update' onClick={function(e){
e.preventDefault();
this.props.onChangeMode('update');
}.bind(this)} >update</a></li>
<li><input onClick={function(e){
e.preventDefault();
this.props.onChangeMode('delete');
}.bind(this)}
type="button" value='delete'></input></li>
</ul>
create를 누르면 a 태그의 기본 동작을 막고 props의 onChageMode 함수를 실행하는데 인자로 create를 전달한다.
update와 delete도 인자로 전달되는 값만 해당 값에 따라 다를 뿐 똑같은 함수가 실행된다.
APP.js
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
})
}.bind(this)}></Control>
그러면 APP.js 에서는 Control 컴포넌트에서 인자를 받아와서(_mode) state의 mode를 받은 인자 값으로 바꿔준다.

이제 해당 버튼을 누를 때마다 mode가 바뀌는 것을 볼 수 있다.
create를 눌렀을 때 텍스트를 입력할 수 있는 폼이 있는 컴포넌트 띄우기
mode가 read면 ReadContent가 create면 CreateContent가 나타날 수 있도록 해주자.
먼저 기존의 content를 ReadContent로 바꿔주고 CreateContent의 틀을 잡아준다.
import React, { Component } from 'react';
class CreateContent extends Component{
render(){
return(
<article>
<h2>Create</h2>
<form>
</form>
</article>
);
}
}
export default CreateContent;
이제 CreateContent의 내용을 채우기 전에 mode에 따라 ReadContent와 CreateContent가 상황에 맞게 나타날 수 있도록 APP.js를 변경하자.
Content 태그가 mode에 따라 변경되어야 하기 때문에 기존에 작성해두었던 조건문을 활용할 것이다. 그리고 기존에 Content 태그가 있던 자리는 변수로 지정해둔다.
{_article}
if(this.state.mode === 'welcome'){
_title = this.state.welcome.title;
_desc = this.state.welcome.desc;
_article = <ReadContent title={_title} desc={_desc}></ReadContent>
} else if(this.state.mode === 'read'){
let i = 0;
while(i < this.state.contents.length){
let data = this.state.contents[i];
if(data.id === this.state.selected_content_id){
_title = data.title;
_desc = data.desc;
break;
}
i = i + 1;
}
_article =<ReadContent title={_title} desc={_desc}></ReadContent>
} else if(this.state.mode === 'create'){
_article = <CreateContent></CreateContent>
}
만약 mode가 welcome이나 read 인 경우 _article이 ReadContent가 되도록 하고 mode가 create인 경우 _article 이 CreateContent가 되도록 한다.
Create 컴포넌트 만들기
이제 Create 컴포넌트에 원하는 내용을 넣을 것이다. form태그로 감싸서 제목 부분, 내용 부분, 제출 버튼을 추가한다.
<article>
<h2>Create</h2>
<form action="/create_process" method="post"
onSubmit={}
>
<p><input type="text" name="title" placeholder="title"></input></p>
<p>
<textarea name="desc" placeholder="description"></textarea>
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
form에 있는 onSubmit이라는 이벤트는 submit 버튼을 클릭했을 때 submit이 포함되어는 form 태그의 onSubmit이라는 이벤트가 설치되어 있다면 실행되도록 약속되어 있다.
<form action="/create_process" method="post"
onSubmit={function(e){
e.preventDefault();
alert('submit');
}.bind(this)}
>
form의 기본 동작의 경우 제출이 되면 action에 있는 페이지로 이동하는 것인데 이것을 preventDefault를 통해 막는다.
이제 사용자가 입력한 값을 App.js 컴포넌트의 state의 contents 값에 추가해야 한다. 그래서! onSubmit 함수를 설정한 다음, submit이 됐을 때 App 컴포넌트에서 <CreateContent>를 호출할 때 onSubmit 이벤트를 실행해야 한다.
//App.js
else if(this.state.mode === 'create'){
_article = <CreateContent onSubmit={function(_title, _desc){
//add content to this.state.contents
}.bind(this)}></CreateContent>
App 컴포넌트에서 이렇게 CreateContent를 실행할 때 CreateContent에서는 form에서 사용자가 입력한 _title 값과 _desc값을 인자로 전달해주면 된다. 그럼 그것을 어떻게 받아올 수 있을까? debugger를 통해 살펴보자.

이런 식으로 디버깅을 통해 value가 저장된 위치를 찾을 수 있다.

콘솔을 통해 찾은 위치를 확인해 보면 정상적으로 value 값을 가져올 수 있다.
이 값을 이용해서 인자로 전해주자
<form action="/create_process" method="post"
onSubmit={function(e){
e.preventDefault();
this.props.onSubmit(
e.target.title.value,
e.target.desc.value
);
}.bind(this)}
>
이제 받아온 값을 state의 content로 저장하면 된다. 그러려면 일단 id 값을 마지막 id 값에서 1 더한 값으로 설정해야 한다. 일단 지금 있는 id의 최고값인 3을 따로 max_content_id로 저장해보자.
class App extends Component {
constructor(props){
super(props);
this.max_content_id = 3;
this.state = {
...
state가 아니라 밖에 값을 저장하는 이유는 이 값은 content의 가장 큰 id 값을 저장하는 용도일 뿐 웹의 ui와는 상관없기 때문이다. 이런 경우 굳이 state안에 값을 저장하지 않아도 된다.
else if(this.state.mode === 'create'){
_article = <CreateContent onSubmit={function(_title, _desc){
//add content to this.state.contents
this.max_content_id = 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>
}
이제 설정한 값들을 이용해서 함수를 설정하면 된다. max_content_id 값에는 1을 더하고 그 값을 id로 그리고 title과 desc값도 가져온다. 하지만! 그냥 this.state로 해서 직접적으로 바꾸면 리액트가 바뀌었는지 모르기 때문에 setState를 통해서 contents의 값을 바뀐 값으로 지정한다.
이렇게 해도 결과는 제대로 나오지만! 이후에 리액트의 성능을 높일 때 아주 까다롭거나 불가능할 수 있다!
이럴 땐 push가 아닌 concat를 사용하는 것이 적절하다.
push의 경우 값을 추가하면 원 배열 자체를 변경해주지만 concat은 원본 배열을 변경하는 것이 아니라 원본 배열에 추가한 값을 넣어서 새로운 배열을 복사하는 것이다.
state 값을 추가할 땐 push처럼 원본을 변경하는 것이 아니라 concat처럼 원본은 그대로 두고 새로운 데이터를 추가하는 것을 사용해야 한다.
let _contents = this.state.contents.concat(
{id: this.max_content_id, title:_title, desc:_desc}
)
this.setState({
contents:_contents
})
push를 사용하면 기존의 원본 데이터에 값을 추가하기 때문에 이후에 성능을 개선할 때 매우 까다로워지지만 concat을 사용하면 원본을 복사하여 새로운 데이터를 만드는 것이기 때문에 성능 개선에 편리하다.

이렇게 원하는 대로 작동된다!!
성능 개선하기
현재 우리 애플리케이션에는 부적절한 부분이 있다. 바로 TOC가 계속해서 호출된다는 것. TOC는 전혀 변경되지 않았음에도 다른 요소를 클릭하거나 변경할 때마다 TOC가 계속 호출된다.
앱이 커질수록 이러한 요소의 개선이 필요한데, 리액트에서도 이를 위한 기능을 만들어두었다.
shouldComponentupdate() 함수이다. 이 함수를 설정하면 render() 보다 먼저 실행되고, 이 함수가 true 땐 render가 실행되지만 false일 땐 실행되지 않는다.
그리고 이 함수는 newProps와 newState 값을 인자로 받는다. 즉,
shouldCopmonentUpdate(newProps, newState){
console.log(newProps.data, this.props.data)
};
이런 식으로 변경된 새로운 데이터 값과 기존의 데이터 값을 함수 내에서 다룰 수 있다. 따라서 이 값들을 이용해서 값이 변했을 때만 함수의 리턴 값이 true가 되어 render 함수가 실행되도록 하고 값이 변하지 않았다면 false가 되어 render 함수가 실행되지 않도록 하여 성능을 개선할 수 있는 것이다.
shouldCopmonentUpdate(newProps, newState){
if(this.props.data === newProps.data){
return false;
}
return true;
};
근데 만약 concat이 아니라 push를 사용했다면??
push를 사용하면 기존의 데이터를 복사해서 저장하지 않고 기존의 데이터 자체를 변경하였기 때문에 새로운 글을 써서 TOC의 값이 달라졌다고 해도, newProps.data와 this.props.data가 같기 때문에 render함수가 실행되지 않는 것이다. 이게 바로 concat을 사용해야 하는 이유이다.
원본을 바꾸지 않는다 = 불변성(immutable)
push를 사용하면서 원본을 바꾸지 않는 방법도 있다. Array.from()을 이용해서 배열 자체를 복사해버리는 것.
let newContents = Array.from(this.state.contents);
newContents.push({id: this.max_content_id, title:_title, desc:_desc});
this.setState({
contents: newContents
});
Array.from은 배열만 사용할 수 있고 객체의 경우 Object.assign을 사용하면 된다.
'개발 공부 > React' 카테고리의 다른 글
React #7 [컴포넌트, CSS, 이벤트, state, props] (0) | 2022.08.23 |
---|---|
React #6 [update, delete] (0) | 2022.08.09 |
React #4 [event 만들기, bind, setState] (0) | 2022.07.13 |
React #3 [component 만들기,React Developer Tools, props, state, key] (0) | 2022.07.13 |
react#2 [샘플 어플리케이션 수정해서 코딩하기, 배포하기] (0) | 2022.07.13 |
props와 state의 차이점

props는 read-only이지만 state는 setState를 통해서 수정이 가능하다.
예를 들어, 현재 Content라는 컴포넌트를 사용하는 APP.js 에서는 title이라는 props를 통해 값을 주입할 수 있다.

하지만 Content 내부에서 title 값을 hi로 바꾸려고 하면 에러가 발생하게 된다.

이렇게 컴포넌트 안에서 자신에게 전달된 props 값을 바꾸는 것은 금지되어있다!
컴포넌트 밖에서만 props를 바꾸는 것이 허용되기 때문에 props가 수정할 수 없는 read-only라는 것!
props와 이벤트

위에 있는 동그라미는 상위 컴포넌트, 아래 동그라미는 하위 컴포넌트이다.
지금까지 만든 컴포넌트로 따지면 상위 컴포넌트는 App.js, 하위 컴포넌트는 Content, Subject, TOC 가 해당된다.
이러한 상위 컴포넌트가 하위 컴포넌트로 값을 전달할 땐 props를 통해 전달하고,
하위 컴포넌트가 상위 컴포넌트의 값을 바꾸고 싶을 땐 이벤트를 통해 값을 변경한다.
상위 컴포넌트 App.js 에서 하위 컴포넌트 TOC로 값을 전달할 땐 data라는 props를 통해서 전달한다.

하지만 하위 컴포넌트 TOC에서 글 목록을 클릭했을 때 APP.js 컴포넌트의 state와 selected_content_id를 바꾸고자 한다면 onChangePage와 같은 이벤트로 상위 컴포넌트의 state 값을 호출하여 state 값을 바꿀 수 있다.
이렇게 지금까지 만든 애플리케이션은 read만 가능하다. 그래서 이제 데이터를 동적으로 추가하고, 수정하고, 삭제하는 방법을 알아보자!
앞으로 배워야 할 것은 CRUD이다.
Create Read Update Delete
이것을 알면 다 아는 것!
create
목표:
글 목록 밑에(TOC와 Content 사이) 생성, 수정, 삭제 버튼을 만든다.
생성 버튼을 누르면 APP의 mode가 create로 바뀌고 Content 컴포넌트가 글을 추가할 수 있는 컴포넌트로 바뀔 것이다.
글을 추가하면 APP 컴포넌트 state의 contents에 글과 id값과 제목 정보가 담긴 객체가 추가될 것이다.
그러면 이렇게 추가된 글에 따라 TOC에 표시될 내용이 달라진다.
글 목록과 content 사이에 create, update, delete 버튼을 만들기
이 버튼들은 Control이라는 컴포넌트 안에 넣어줄 것이다.
import React, { Component } from 'react';
class Control extends Component{
render(){
return (
<ul>
<li><a href='/create'>create</a></li>
<li><a href='/update'>update</a></li>
<li><input type="button" value='delete'></input></li>
</ul>
);
}
}
export default Control;
delete 버튼만 a태그가 아닌 input 태그인 이유는 만약 사용자가 웹페이지에 방문했을 때 링크에 더 빠르게 접속할 수 있도록 링크가 미리 실행되는 기능을 사용한다면? delete 가 사용돼버리면 내용이 삭제되어버린다. 이러한 상황을 막기 위해 delete는 input 태그를 사용한다.
이제 Control 컴포넌트 안에 있는 버튼을 클릭하면 그에 따라 모드가 바뀌는 이벤트가 발생하도록 하기 위해 이벤트를 설정해보자.
//Control.js
<ul>
<li><a href='/create' onClick={function(e){
e.preventDefault();
this.props.onChangeMode('create');
}.bind(this)}>create</a></li>
<li><a href='/update' onClick={function(e){
e.preventDefault();
this.props.onChangeMode('update');
}.bind(this)} >update</a></li>
<li><input onClick={function(e){
e.preventDefault();
this.props.onChangeMode('delete');
}.bind(this)}
type="button" value='delete'></input></li>
</ul>
create를 누르면 a 태그의 기본 동작을 막고 props의 onChageMode 함수를 실행하는데 인자로 create를 전달한다.
update와 delete도 인자로 전달되는 값만 해당 값에 따라 다를 뿐 똑같은 함수가 실행된다.
APP.js
<Control onChangeMode={function(_mode){
this.setState({
mode:_mode
})
}.bind(this)}></Control>
그러면 APP.js 에서는 Control 컴포넌트에서 인자를 받아와서(_mode) state의 mode를 받은 인자 값으로 바꿔준다.

이제 해당 버튼을 누를 때마다 mode가 바뀌는 것을 볼 수 있다.
create를 눌렀을 때 텍스트를 입력할 수 있는 폼이 있는 컴포넌트 띄우기
mode가 read면 ReadContent가 create면 CreateContent가 나타날 수 있도록 해주자.
먼저 기존의 content를 ReadContent로 바꿔주고 CreateContent의 틀을 잡아준다.
import React, { Component } from 'react';
class CreateContent extends Component{
render(){
return(
<article>
<h2>Create</h2>
<form>
</form>
</article>
);
}
}
export default CreateContent;
이제 CreateContent의 내용을 채우기 전에 mode에 따라 ReadContent와 CreateContent가 상황에 맞게 나타날 수 있도록 APP.js를 변경하자.
Content 태그가 mode에 따라 변경되어야 하기 때문에 기존에 작성해두었던 조건문을 활용할 것이다. 그리고 기존에 Content 태그가 있던 자리는 변수로 지정해둔다.
{_article}
if(this.state.mode === 'welcome'){
_title = this.state.welcome.title;
_desc = this.state.welcome.desc;
_article = <ReadContent title={_title} desc={_desc}></ReadContent>
} else if(this.state.mode === 'read'){
let i = 0;
while(i < this.state.contents.length){
let data = this.state.contents[i];
if(data.id === this.state.selected_content_id){
_title = data.title;
_desc = data.desc;
break;
}
i = i + 1;
}
_article =<ReadContent title={_title} desc={_desc}></ReadContent>
} else if(this.state.mode === 'create'){
_article = <CreateContent></CreateContent>
}
만약 mode가 welcome이나 read 인 경우 _article이 ReadContent가 되도록 하고 mode가 create인 경우 _article 이 CreateContent가 되도록 한다.
Create 컴포넌트 만들기
이제 Create 컴포넌트에 원하는 내용을 넣을 것이다. form태그로 감싸서 제목 부분, 내용 부분, 제출 버튼을 추가한다.
<article>
<h2>Create</h2>
<form action="/create_process" method="post"
onSubmit={}
>
<p><input type="text" name="title" placeholder="title"></input></p>
<p>
<textarea name="desc" placeholder="description"></textarea>
</p>
<p>
<input type="submit"></input>
</p>
</form>
</article>
form에 있는 onSubmit이라는 이벤트는 submit 버튼을 클릭했을 때 submit이 포함되어는 form 태그의 onSubmit이라는 이벤트가 설치되어 있다면 실행되도록 약속되어 있다.
<form action="/create_process" method="post"
onSubmit={function(e){
e.preventDefault();
alert('submit');
}.bind(this)}
>
form의 기본 동작의 경우 제출이 되면 action에 있는 페이지로 이동하는 것인데 이것을 preventDefault를 통해 막는다.
이제 사용자가 입력한 값을 App.js 컴포넌트의 state의 contents 값에 추가해야 한다. 그래서! onSubmit 함수를 설정한 다음, submit이 됐을 때 App 컴포넌트에서 <CreateContent>를 호출할 때 onSubmit 이벤트를 실행해야 한다.
//App.js
else if(this.state.mode === 'create'){
_article = <CreateContent onSubmit={function(_title, _desc){
//add content to this.state.contents
}.bind(this)}></CreateContent>
App 컴포넌트에서 이렇게 CreateContent를 실행할 때 CreateContent에서는 form에서 사용자가 입력한 _title 값과 _desc값을 인자로 전달해주면 된다. 그럼 그것을 어떻게 받아올 수 있을까? debugger를 통해 살펴보자.

이런 식으로 디버깅을 통해 value가 저장된 위치를 찾을 수 있다.

콘솔을 통해 찾은 위치를 확인해 보면 정상적으로 value 값을 가져올 수 있다.
이 값을 이용해서 인자로 전해주자
<form action="/create_process" method="post"
onSubmit={function(e){
e.preventDefault();
this.props.onSubmit(
e.target.title.value,
e.target.desc.value
);
}.bind(this)}
>
이제 받아온 값을 state의 content로 저장하면 된다. 그러려면 일단 id 값을 마지막 id 값에서 1 더한 값으로 설정해야 한다. 일단 지금 있는 id의 최고값인 3을 따로 max_content_id로 저장해보자.
class App extends Component {
constructor(props){
super(props);
this.max_content_id = 3;
this.state = {
...
state가 아니라 밖에 값을 저장하는 이유는 이 값은 content의 가장 큰 id 값을 저장하는 용도일 뿐 웹의 ui와는 상관없기 때문이다. 이런 경우 굳이 state안에 값을 저장하지 않아도 된다.
else if(this.state.mode === 'create'){
_article = <CreateContent onSubmit={function(_title, _desc){
//add content to this.state.contents
this.max_content_id = 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>
}
이제 설정한 값들을 이용해서 함수를 설정하면 된다. max_content_id 값에는 1을 더하고 그 값을 id로 그리고 title과 desc값도 가져온다. 하지만! 그냥 this.state로 해서 직접적으로 바꾸면 리액트가 바뀌었는지 모르기 때문에 setState를 통해서 contents의 값을 바뀐 값으로 지정한다.
이렇게 해도 결과는 제대로 나오지만! 이후에 리액트의 성능을 높일 때 아주 까다롭거나 불가능할 수 있다!
이럴 땐 push가 아닌 concat를 사용하는 것이 적절하다.
push의 경우 값을 추가하면 원 배열 자체를 변경해주지만 concat은 원본 배열을 변경하는 것이 아니라 원본 배열에 추가한 값을 넣어서 새로운 배열을 복사하는 것이다.
state 값을 추가할 땐 push처럼 원본을 변경하는 것이 아니라 concat처럼 원본은 그대로 두고 새로운 데이터를 추가하는 것을 사용해야 한다.
let _contents = this.state.contents.concat(
{id: this.max_content_id, title:_title, desc:_desc}
)
this.setState({
contents:_contents
})
push를 사용하면 기존의 원본 데이터에 값을 추가하기 때문에 이후에 성능을 개선할 때 매우 까다로워지지만 concat을 사용하면 원본을 복사하여 새로운 데이터를 만드는 것이기 때문에 성능 개선에 편리하다.

이렇게 원하는 대로 작동된다!!
성능 개선하기
현재 우리 애플리케이션에는 부적절한 부분이 있다. 바로 TOC가 계속해서 호출된다는 것. TOC는 전혀 변경되지 않았음에도 다른 요소를 클릭하거나 변경할 때마다 TOC가 계속 호출된다.
앱이 커질수록 이러한 요소의 개선이 필요한데, 리액트에서도 이를 위한 기능을 만들어두었다.
shouldComponentupdate() 함수이다. 이 함수를 설정하면 render() 보다 먼저 실행되고, 이 함수가 true 땐 render가 실행되지만 false일 땐 실행되지 않는다.
그리고 이 함수는 newProps와 newState 값을 인자로 받는다. 즉,
shouldCopmonentUpdate(newProps, newState){
console.log(newProps.data, this.props.data)
};
이런 식으로 변경된 새로운 데이터 값과 기존의 데이터 값을 함수 내에서 다룰 수 있다. 따라서 이 값들을 이용해서 값이 변했을 때만 함수의 리턴 값이 true가 되어 render 함수가 실행되도록 하고 값이 변하지 않았다면 false가 되어 render 함수가 실행되지 않도록 하여 성능을 개선할 수 있는 것이다.
shouldCopmonentUpdate(newProps, newState){
if(this.props.data === newProps.data){
return false;
}
return true;
};
근데 만약 concat이 아니라 push를 사용했다면??
push를 사용하면 기존의 데이터를 복사해서 저장하지 않고 기존의 데이터 자체를 변경하였기 때문에 새로운 글을 써서 TOC의 값이 달라졌다고 해도, newProps.data와 this.props.data가 같기 때문에 render함수가 실행되지 않는 것이다. 이게 바로 concat을 사용해야 하는 이유이다.
원본을 바꾸지 않는다 = 불변성(immutable)
push를 사용하면서 원본을 바꾸지 않는 방법도 있다. Array.from()을 이용해서 배열 자체를 복사해버리는 것.
let newContents = Array.from(this.state.contents);
newContents.push({id: this.max_content_id, title:_title, desc:_desc});
this.setState({
contents: newContents
});
Array.from은 배열만 사용할 수 있고 객체의 경우 Object.assign을 사용하면 된다.
'개발 공부 > React' 카테고리의 다른 글
React #7 [컴포넌트, CSS, 이벤트, state, props] (0) | 2022.08.23 |
---|---|
React #6 [update, delete] (0) | 2022.08.09 |
React #4 [event 만들기, bind, setState] (0) | 2022.07.13 |
React #3 [component 만들기,React Developer Tools, props, state, key] (0) | 2022.07.13 |
react#2 [샘플 어플리케이션 수정해서 코딩하기, 배포하기] (0) | 2022.07.13 |