이전에 사용한 함수 push()
와 concat()
을 확인해보자.
// push()
var a = [1,2];
a.push(3);
console.log(a);
---
(3) "1, 2, 3"
위 console 창을 확인하면 a 배열
은 [1, 2, 3]
이다.
이 코드를 push()
를 사용하지 않고 concat()
을 사용한다면 원본을 바꾸지 않기 때문에 a
의 값은 여전히 [1, 2]
을 유지한다.
// concat()
var a = [1,2];
var b = a.concat(3);
console.log(a,b);
---
(2) "1, 2",
(3) "1, 2, 3"
concat
의 리턴
값을 b
로 담고
a
와 b
를 비교하면
concat()
은 원본을 바꾸지 않고 새로 만든 복제본이라는 것 을 알 수 있다.
setState()
에 어떤 값을 수정할 때원본
을 수정하지 말고원본
에복제본
을 수정해서- 그
복제본
을setState()의 값
으로 하는 것이 이번 시간의 핵심이다.
현재 지금 만지작 거리고 있는 애플리케이션은 조금 불합리한 면을 가지고 있다.
글 목록인 <Navi>
컴포넌트가 화면에 표시되기 위해서 contents
가 담고 있는 배열들이 필요하다.
이 배열의 내용이 바뀌었다면 <Navi>
컴포넌트와 상관없는 일이 진행되고 있는데도
<Navi>
컴포넌트의 render
는 호출이 되는 것은 매우 불합리한 상황일 수 있다.
페이스북에서는 성능을 향상시키고 싶을 때
어떤 컴포넌트의render 함수
가 실행될지 실행되지 않을지를 개발자가 결정할 수 있도록shouldComponentUpdate
라는 특수한 약속의 함수를 제공한다.
shouldComponentUpdate(){
colsole.log("===>Navi render shouldComponentUpdate!!!");
return true;
}
위 코드를 추가해서 어떤 상태가 바뀔 때마다 shouldComponentUpdate 함수
가 호출된 다음에 render 함수
가 호출되는 것을 확인할 수 있다.
이전에는 Navi 컴포넌트의 state 값이 바뀌면 그 자식 컴포넌트들은 모두 render가 호출되었다.
shouldComponentUpdate
의 리턴 값을 무조건 flase
로 변경하면
shouldComponentUpdate
는 호출되지만 render
함수는 호출되지 않는다.
심지어 글을 작성해도 rneder()
함수가 호출되지 않았기 때문에 글목록은 반영되지 않는다.
shouldComponentUpdate
함수는 "newProps"
, "newState"
두 개의 매개 변수를 갖도록 약속되어 있다.
이름처럼 Navi
컴퍼넌트의 props
(속성) 가 바뀌었을 때 그 바뀐 값, state
가 바뀌었을 때 그 바뀐 state
값이 들어온다.
shouldComponentUpdate(){
console.log('===> Navi render shouldComponentUpadate!!!'
,newProps.data // 변경 후
,this.props.data // 변경 전
);
debugger; // 디버거로 확인해보기
return true;
}
변경 된 값을 확인하기 위해 shouldComponentUpdate
함수를 위 코드와 같이 변경한다.
- 결과
글 목록을 클릭하면 newProps.data
와 this.props.data
는 동일한 것을 확인할 수 있다.
하지만 글을 작성해보면 newProps.data
는 원소가 4개인 배열이고, this.props.data
는 원소가 3개인 데이터다.
즉, 첫 번째 인자를 통해서 바뀐 값을 알 수 있고 두번째 인자를 통해서 현재 값을 알 수 있다.
- 정리
1. render 이전에 shouldComponentUpdate()가 실행된다.
2. shouldComponentUpdate의 리턴값이 true면 render()가 호출되고 false면 render가 호출되지 않도록 약속되어 있다.
3. shouldComponentUpdate는 새롭게 바뀐 값과 이전 값에 접근할 수 있다.
이것을 종합해 Navi
컴포넌트로 들어오는 data
라는 prorps
의 값이 바뀌었을 때
this.props.data
값과 newProps.data
의 값이 서로 같다면 바뀐게 없으므로 false
,
그렇지 않으면 true
를 리턴하도록 변경한다.
ShouldComponentUpdate(){
console.log("===>Navi render shouldComponentUpdate!!!"
, newProps.data
, this.props.data
);
if(this.props.data === newProps.data){
console.log("render : false");
return false;
}
console.log("render : true");
return true;
}
- 기존
<Navi>
영역에 있는 컨텐츠<a> 링크
를 클릭하면
- Alpha 링크 클릭
render
:false
실행해보면 Navi
에 있는 목록들을 클릭할 때 render
함수는 호출되지 않는다.
하지만 글을 작성할 때는 이전 값과 바뀐 값이 서로 다르기 때문에,
리턴값은 true
가 되고 render
함수가 호출된다.
만약 글 작성 코드를 concat() 이 아닌 push() 방식으로 구현을 했다면 기존의 this.state.contents의 원본을 바꾸게 된다.
push()
-->CreateArti
의onSubmit
이벤트를push()
로 작업할 경우
... if(mode === "create")
<CreateArti.js> onSubmit() 이벤트를 통해 속성에게 새로운값 전달
콘텐츠 id 값 + 1
[원본값].push([새로운값])
this.setState({...})
render : false
[원본값]
은shouldComponentUpdate
가 체크하기 전에
이미[원본값]
이 수정 된 상태이므로, 원본과 비교할 새로운 값이 같다고 인식할 수 밖에 없다.
shouldComponentUpdate
입장 :
원본 값과 새로운 값이 완전히 일치하니까 render 이밴트를 실행하지 말아야지.
- 즉 비교할 원본대상이 없다.
concat()
-->CreateArti
의onSubmit
이벤트를concat()
로 작업할 경우
... if(mode === "create")
<CreateArti.js> onSubmit() 이벤트를 통해 속성에게 새로운값 전달
// 임시 변수 저장소에 concate활용
var _contents = this.staet.contents.concat({객체에 새로운 값 주입})
this.setState({...})
render : true
_contents
라고 하는 임시 변수에 새로운 값을 넣고,
this.set.Staete({contents : _contents})
가 실행하면서 steat가 바뀌고
App.js > Navi컴포넌트 props 영역은
:
data={this.state.contents} 로 인해 새로운 데이터가 주입되고
Navi.js > shouldComponentUpdate 이밴트 실행
render : true
concat()을 활용하면 원본값과 새로운 값을 비교할 수 있다.
위와같이 새로운 데이터는 임시 데이터에 저장하고 원본에는 영향을 주지 않았기 때문에
shouldComponentUpdate
함수가 데이터를 비교하고 두 값이 같지 않기 때문에
render : true
를 출력하고 해당 컴포넌트를 새롭게 렌더링 하게 된다.