도움말 - 글감 수집하기 (인용)

도움말 - 부분 리뷰 작성하기

리액트(React) 이해 기초 - Component vs PureComponent vs Functional Component

리액트(React)에서 컴포넌트를 만드는 방법에는 크게 클래스 기반(React.Component, React.PureComponent를 확장(extends)해서 사용)과 함수 기반(Functional Stateless Component)으로 나눌 수 있습니다. (React.createClass는 deprecated 되었고, 16 버전에서는 없어지기 때문에 제외 한다.) 이 글에서는 이 세가지 방법의 다른점을 비교 해보고(문법(syntax)는 제외), 퍼포먼스에 대한 얘기를 조금 해보도록 하겠습니다.


먼저, 클래스 기반 컴포넌트 (React.Component, React.PureComponent)에 대해 알아보자. 사실, 두개는 shouldComponentUpdate 라이프 사이클 메소드를 다루는 방식을 제외하곤 동일하다. 즉, PureComponentshouldComponentUpdate 라이프 사이클 메소드가 이미 적용 된 버전의 React.Component 클래스라고 보면 된다.

React.Component를 확장(extends)해서 컴포넌트를 만들 때, shouldComponentUpdate 메쏘드를 별도로 선언하지 않았다면, 컴포넌트는 props, state 값이 변경되면 항상 리렌더링(re-render) 하도록 되어 있다.

하지만, React.PureComponent를 확장해서 컴포넌트를 만들면, shouldComponentUpdate 메쏘드를 선언하지 않았다고 하더라도, PureComponent 내부에서 props와 state를 shallow level 안에서 비교 하여, 변경된 값이 있을 시에만 리렌더링 하도록 되어 있다.

이를 제외하곤 React.Component와 React.PureComponent의 다른 점은 없다. 그렇다면, 함수형 컴포넌트가 클래스 기반의 컴포넌트와 다른점은 무엇일까? 함수형 컴포넌트는 클래스 기반의 컴포넌트와 달리, state, 라이프 사이클 메소드(componetDidMount, shouldComponentUpdate 등등..)와 ref 콜백을 사용 할 수 없다는데 있다(context는 사용 할 수 있다). 언뜻 보면, 함수형 컴포넌트가 state도 없고, 라이프 사이클도 신경쓰지 않기 때문에, 클래스 기반의 컴포넌트 보다 퍼포먼스가 뛰어날 것이라고 예상 하지만 실제로는 그렇지 않다.

아래의 글에서도 확인 할 수 있듯이, 함수형 컴포넌트가 클래스 컴포넌트의 퍼포먼스보다 우위에 있다고 하기엔 어렵다. 오히려, React.PureComponent가 React.Component와 함수형 컴포넌트 보다 더 빠른 걸 알 수 있다. React.PureComponent는 shouldComponentUpdate를 통해 리렌더링을 최소화 하는 로직이 들어가 있으니 그렇다 치더라도 함수형 컴포넌트와 클래스 컴포넌트의 속도 차이가 없는 것은 의외라고 생각 할 수 있다.

사실, 그 이유는 의외로 간단한데, 함수형 컴포넌트도 결국엔 클래스 기반 컴포넌트로 래핑(wrapping)되기 때문이다. 아래 Dan의 트윗을 먼저 확인해보자. 향 후에 16 버전 또는 더 미래에는 함수형 컴포넌트의 퍼포먼스 우위가 있을 수 있지만 현재로는 아니다.


그렇다면, 항상 React.PureComponent를 사용 하는게 좋다고 할 수 있을까? 대답은 당연히 아니다. 위에서도 언급 했지만, PureComponent는 shallow level로만 데이터를 비교하기 때문에, nested object 등의 변경된 데이터는 감지하지 못하기 때문에 React.Component의 shouldComponentUpdate 직접 다뤄야 한다. 또한, 퍼포먼스 적으로도 모든 컴포넌트에 PureComponent를 사용 하는 것은 오히려 앱을 더 느리게 할 수도 있다.



클래스 컴포넌트(state, lifecycle, ref)가 필요한 상황이 아니라면 항상 컴포넌트는 함수형으로 만드는게 좋다

그렇다면, 함수형 컴포넌트를 그대로 유지하면서 리렌더링을 최소화 할 수 있는 방법은 없을까? 리액트 유틸리티(higher order components) 라이브러리인 recompose 등을 사용 하면 함수형 컴포넌트를 그대로 유지하면서 PureComponent(pure)의 효과를 누리거나 그보다 더 나은 퍼포먼스 상에 이점(onlyUpdateForKeys, onlyUpdateForPropTypes)을 가질 수 있는 함수들이 있기 때문에 이런 라이브러리를 적극 활용 하면 함수형 컴포넌트를 그대로 유지하면서 리렌더링을 최소화 할 수 있다.

pure HOC(Higher Order Component)의 경우 React.PureComponent와 로직상 같고, onlyUpdateForKeys, onlyUpdateForPropTypes HOC는 특정 props 값이 변경 되었을 때만 리렌더링을 하도록 하기 때문에, pure, React.PureComponent 보다 퍼포먼스 상에 우위를 가져 갈 수 있다.


리액트의 세 가지(React.Component, React.PureComponent, Functional Component) 컴포넌트의 다른 점과 리렌더링을 다루는 방법에 대해 얘기했습니다. 리액트를 처음 접하면 쉽게 오해 할 수 있는 부분 인데, 이 글을 통해 조금 더 리액트를 이해 할 수 있었으면 좋겠습니다.

리뷰