-
`React.PureComponent` 이놈을 알아보자.간단정리 2020. 6. 2. 14:27
PureComponent란?
React에서는 3가지 Component들이 존재한다.
- React.Component
class Ryuk extends Component { render() { return( <div> 안냐세여 </div> ) } }
- React.PureComponent
class Ryuk extends PureComponent { render() { return( <div> 안냐세여 </div> ) } }
- Function Component
const Ryuk = () => { return ( <div> 안냐세여 </div> ); };
각 컴포넌트들의 세세한 특징들이 있겠지만, 우리는 PureComponent 와 Component의 차이만 간단하게 짚어보자. 열심히 검색을 하다보면 두 컴포넌트의 차이는 shouldComponentUpdate() 라이프 사이클이라는 답을 찾을 수 있을 것이다.
- React.PureComponent는 React.Component에 shouldComponentUpdate()가 적용된 버전이다.
(엄밀히 말하면 shouldComponentUpdate()안에 얕은비교가 적용된 버전이다.)
아직 만들지도 않았는데.. 내 웹이 버벅거리네 ㅎㅎ
React의 state를 사용 하던, 좀 더 구조화해서 사용할 수 있는 redux를 사용하던, 좀 더 쉽게 쓸 수 있는 mobx 를 사용하던, 우리는 state가 변경 될 때마다 컴포넌트들이 다시 render 되는 모습을 볼 수 있다.
위의 gif 처럼 자식2 (두 번째 Input창)의 값이 변경 되지 않아도, 자식1의 변경으로 인하여 Re-render되는 형상이 가볍게만 느껴지지 않는다. 혹여 render하면서 반응형을 체크 하거나, 또 그 하위 자식들이 많을 경우 이는 분명 성능 문제를 일으킬 것이다.
그래서.. PureComponent란 말이다.
위에서 언급했듯이 PureComponent는 Component shouldComponentUpdate()안에 얕은 비교가 적용된 버전이다.
얕은 비교 (shallow-compare)
PureComponent는 shouldComponentUpdate() 라이프 사이클에서 얕은 비교를 통해 업데이트 여부를 결정한다.
- 변수와 문자열에서는 값을 비교한다.
- 객체에서는 reference 값을 비교한다.
shouldComponentUpdate() { if(아니 그래서 너 진짜 바뀌었니?) { 그렇다면 render() 하렴; } else { 그렇다면 render 하지마렴; } }
즉, 우리가 직접 shouldComponentUpdate 에서 변경 여부를 확인하고 Re-render 여부를 결정 지을 수 있지만 그렇기에는 공수가 많이 들기 때문에 PureComponent가 생겨났고, 언제부턴가 '잘 모르면 그냥 PureComponent써..' 라는 말이 생겨난 것 같다.
1차 정리
- PureComponent는 변경 된 사항을 자동으로 체크하고, Re-render 여부를 결정지어준다. 물론, 이는 우리가 일반 Component를 사용하고, shouldComponentUpdate() 라이프 사이클에서 정의 할 수 있다.
- state를 잘 못 사용하면, 유저의 자그마한 손 짓 하나에 우리의 웹이 다시 render 되는 매직을 볼 수 있다. 그렇기에 우리는 Component의 역할을 잘 분리해야하고, PureComponent를 잘 활용해야한다.
좋아. 그럼 언제 써야하나?
@observer class Parent extends Component { @observable compoOneValue = ""; @observable compoTwoValue = ""; onChangeCompoOne = (event: React.FormEvent<HTMLInputElement>) => { this.compoOneValue = event.target.value; }; onChangeCompoTwo = (event: React.FormEvent<HTMLInputElement>) => { this.compoTwoValue = event.target.value; }; render() { return( <div> <Child1 value={this.compoOneValue} onChangeValue={this.onChangeCompoOne} /> <Child2 value={this.compoTwoValue} onChangeValue={this.onChangeCompoTwo} /> </div> ) } }
- 난 보통 위와 같은 페이지 구성을 할 때, 위와 같은 구성으로 만들 것 같다.
- 데이터를 컨트롤 해야하기 때문에 데이터는 Parent 컴포넌트에서 관리하고, Child의 Props로 넘겨줄 것이다.
[Test1] 부모만 PureComponent (자식들은 일반 Component)
- 부모만 PureComponent일 때는 똑같은 상황(자식 한명이 바뀌어도 모두 Re-render)이 발생 된다.
[Test2] 자식1만 PureComponent (부모, 자식2 일반 Component)
- PureComponent 자식1 을 변경 했더니, 다른 자식도 Re-render 되었다.
- 하지만 자식2를 변경 했더니, PureComponent인 자식1은 Re-render 되지 않았다.
[Test3] 자식 모두 PureComponent (부모 일반 Component)
- 자식 모두 PureComponent로 선언 하니, 서로의 영향을 받지 않았다.
- PureComponent는 변경 된 점이 있는지 체크하고, Render 여부를 판단하기 때문에 변경이 되지 않은 PureComponent 자식을 Re-render 시키지 않았다.
[Test4] 모두 PureComponent
- 부모 또한, PureComponent 일 때도 Test3 과 같은 방식으로 Render 되었다.
- 여기서 우린 부모 Component를 PureComponent로 설정 하는 것은 낭비 라는 것을 어렴풋이 알 수 있다.
하지만 의문이 든다.
- 부모 Component의 "부모 Render" 로그가 꼭 찍혀야하는 건가?
- 자식이 변경 되면, 일단 부모는 Re-render 되어야 할까?
실제 웹페이지 개발을 하다 보면, 위와 같은 예시보다 더 복잡한 구조가 나올 것이다.
우린 어디까지 부모라고 보아야하고,
어디를 PureComponent로 설정해야 할까?- 단순하게 생각하면 같은 계층에 컴포넌트가 존재한다면 PureComponent로 만들 것 같다.
하지만 이 부분은 단순한 문제는 아닌 것 같다. 컴포넌트들의 구조를 짜면서 어디 까지를 그룹화 시킬 것이고, 각 Component들이 어디 까지 영향을 미치게 할지 설계를 하는 부분에서 PureComponent를 정할 수 있을 것이다.
이런 문제로 "모르면 PureComponent 써"라는 말이 나온 것 같다.
[더 많은 비용 발생]
(PureComponent를 쓰지 않아, 무분별한 Re-render가 발생) > (의미 없는 PureComponent들의 얕은 비교 연산)
위 조건이 true 일 확률이 더 높기 때문일 것이다.
인터넷에 존재하는 한 페이지의 예제로는 PureComponent를 이해하기 쉽지 않기 때문에 글을 여기서 마무리 하고 싶지 않지만, 단순한 예제를 작성만으로 'PureComponent는 이렇게 사용해야합니다!'를 이해시키긴 힘들 것 같아 여기까지 적어야겠다.
하지만 위 TestCase를 이해하게 된다면 어느 Component를 PureComponent로 선언해주어야 할지 알게 될 것이고, 이러한 생각을 할 수 있다면 좀 더 효율적인 구조를 짤 수 있는 생각을 할 수 있게 된다고 믿는다.
결론
- Depth가 깊어지면 깊어질 수록 PureComponent는 단순 하지만 어렵다. 하지만, TestCase를 이해하게 되면 어떻게 동작 되는지 감이 잡힐 것 같다.
- 이해가 되지 않는다면 Component 보단 PureComponent를 쓰자. 굳이 변화를 비교 할 필요없는 Component들이 PureComponent가 되어 비교를 진행하는 연산 보다는 무분별하게 Re-render 되는 비용이 분명 클 것이다.
'간단정리' 카테고리의 다른 글
[JS] 유형 비교 `==`와 엄격한 비교 `===`의 차이점 (0) 2020.07.07 [JS] undefined / null / NaN 차이점 (0) 2020.07.07 MobX @action @computed 간단 정리 (1) 2020.07.03