[React] 렌더링 최적화

yongkini ·2021년 12월 13일
2

React

목록 보기
1/19

React 렌더링 최적화


: 스타트업에서 일할 때도 어떻게하면 이.. '렌더링 최적화'를 잘할 수 있을까를 엄청 고민했던 것 같다. 사실 개인 프로젝트를 하다보면 데이터의 수가 적어서 굳이 렌더링 최적화의 필요성을 '체감'할 수 없는 경우가 많다. 그러나, 데이터가 많은 부분에서 인피니트 스크롤 기능을 만든다던지(내가 제일 많이 만들어본 것..ㅎ)의 상황이 생기면 얘기가 달라진다. 오늘은 그러한 부분에 있어서 리액트에서 렌더링 최적화를 하는 다양한 방법에 대해 정리해두는 블로깅을 하고자 한다.

useMemo

: 특정 state를 기준으로 함수를 이용해 연산을 수행, 그리고 그 수행한 return 값을 렌더링할 때에 있어서 특정 state가 변하지 않았음에도 해당 컴포넌트의 다른 state 혹은 다른 상황의 발생으로 리렌더링이 발생했을 때, 위에서 말한 특정 state가 안변했음에도 함수를 이용해 재연산을 수행하게 된다. 이 때, 그 연산의(함수) 코스트가 높다면 굉장히 비효율적이므로 useMemo(Memoized)를 이용해 이러한 쓸데없는 비용을 방지할 수 있다. 즉, useMemo(함수, [특정 state]); 이렇게 해주면 특정 state가 변하지 않는 이상 해당 함수의 리턴 값을 캐싱하면서 리렌더링해도 특정 state가 변한게 아니라면 재연산하지 않는다.
** 참고 : https://react.vlpt.us/basic/17-useMemo.html

가상화된 List

: 실제로 개발할 때 마주쳤던 이슈인데, 무한 스크롤 등으로 커버하는 대량의 자료를 계속해서 리렌더링하게 되면 이 또한 비용 낭비가 된다. 이에 따라 실제로 유저가 viewport 상에서 보는 부분만 렌더링하고, 나머지 부분은 가리는 스킬(?)을 써서 비용 낭비를 막는다(이러한 스킬을 windowing이라고 한다). 이를 위한 라이브러리 들이 있는데 이중에 react-virtualized, react-window 라는 라이브러리가 있다.

React.PureComponent

: 쉽게 말해 setState를 썼다고 무조건 리렌더링 하지 않도록 만드는 것이다. 사실 setState를 하더라도 실제로 데이터는 안바뀌는 경우가 있을 수 있다. 예를 들어, input value를 가지고 setState를 하는 로직이 있다 했을 때, setState를 하더라도 input value가 안바뀌었으면 굳이 리렌더링을 할 필요가 없다. 따라서, 이 때 얕은 비교(주소값 비교가 아닌 단지 값 비교)를 통해 둘의 차이가 있으면 리렌더링하고 없으면 안하는 식으로 작동한다. class component의 shouldComponentUpdate 의 역할과 비슷함.

** 이 때, pureComponent를 함수형 컴포넌트 개발 방식에서는 어떻게 쓸까? : React.memo가 이와 유사한 기능을 함(only props 비교) + 커스텀 비교 함수를 만들 수도 있음.

Web Worker

: Web Worker는 script 실행을 메인 쓰레드가 아니라 백그라운드 쓰레드에서 실행할 수 있도록 해주는 기술 입니다. 이 기술을 통해 무거운 작업을 분리된 쓰레드에서 처리할 수 있으며, 이를 통해 메인 쓰레드(일반적으로 UI 쓰레드)는 멈춤, 속도저하 없이 동작할 수 있게 됩니다. 이는 JS가 '싱글 스레드'인 점에서 나타난 문제점이고 해결 방법이다.

코드 스플리팅 & 멀티 번들링 with react.lazy

위와 같이 React.lazy를 이용해 비동기적으로 번들을 생성해 코드 스플리팅 및 멀티 번들링을 가능케하여 부하를 줄여줄 수 있다. 이 때, React.lazy()를 통해 가져오는 컴포넌트는 Suspense로 감싸줘야한다.

useCallback

: 위에서 useMemo를 통해 props를 얕은 비교로 비교 후 변하지 않았으면 리렌더링을 하지 않는 방식을 말했었다. 하지만, 이 때 props가 함수면 문제가 생긴다. 만약에 함수가 props로 전달된다면 props를 전달할 때마다 새로운 인스턴스의 함수를 전달받게 되는데, 그러면 얕은 비교를 한다는 측면에 있어서 주소값이 다를 것이기에 다른 것으로 판단하고 리렌더링 하게 된다. 이를 막기 위한 것이 useCallback이다.

useCallback(함수, [state]); 이런식으로 쓰는데, useMemo 처럼 특정 state가 바뀔 때만 세팅을 해놓음으로써 함수를 재생성한다. 즉, state로 지정한 state가 변하지 않으면, 해당 함수가 포함된 컴포넌트가 리렌더링돼도 해당 함수는 새로 생성하지 않게 되고, 이러한 useCallback으로 감싼 함수를 props로 받는 컴포넌트에서도 참조값이 변하지 않았기 때문에 React.memo를 써도 리렌더링 하던 것을 안하게 된다. 그리고 만약 지정해놓은 state가 변하면 해당 함수를 재생성하게 되고, React.memo에서도 이게 캐치업이 돼서 이 경우에는 리렌더링을 하도록 한다.

Reference

profile
완벽함 보다는 최선의 결과를 위해 끊임없이 노력하는 개발자

0개의 댓글