React 성능 최적화

dogyeong·2020년 12월 27일
3

렌더링 최적화

리액트에서 불필요한 렌더링을 최소화하여 성능을 최적화할 수 있습니다. 성능 최적화를 시도해보면서 공부해보겠습니다.


React Developer Tools

https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi

페이스북에서 만든 리액트 디버깅 툴입니다. 컴포넌트 트리를 볼 수도 있고, 프로파일링 기능도 제공하여 성능 최적화 시 많은 도움을 받을 수 있습니다.


성능 개선 지표

일단 성능을 개선하려면 지금 성능이 좋은지, 안좋은지 판단할 수 있어야 합니다. 리액트에서 성능이 안좋다는 것은 무슨 말일까요?

대부분의 경우 화면을 렌더링하는데 많은 시간이 걸리거나 불필요한 렌더링이 발생하는 경우에 성능이 좋지 않다고 판단하는 것 같습니다.

그렇다면 React DevTools로 성능이 저하되는 부분을 찾아봅시다.


성능 측정

Dec-27-2020 21-15-36

위의 이미지처럼 React DevTools에는 렌더링되는 부분을 시각적으로 표현해주는 기능이 있습니다. 반짝이는 부분이 해당 컴포넌트가 렌더링되었다는 의미입니다.

위 상황은 Form 위에 Modal을 띄운 상황이고, Modal에 값을 입력할 때 아래 겹쳐져있는 Form에서도 렌더링이 일어난다는 것을 알 수 있습니다.

React DevTools의 Profiler 기능으로 렌더링 과정을 더 자세하게 측정할 수 있습니다.

스크린샷 2020-12-27 오후 6 09 35

하나의 값을 입력할 때의 과정을 측정해보니 총 5.9ms 정도 걸렸고 Form을 렌더링하는데 2.1ms, Modal을 렌더링하는데 3.7ms 정도 걸린것으로 보입니다.


성능 개선

왜 이런 일이 발생할까요? Modal과 Form의 부모 컴포넌트인 LogInContainer에서 상태를 가지고 있고, Modal에서 값을 입력하면 그 상태가 변경되어서 Modal과 Form 둘 다 리렌더링되기 때문입니다.

React.memo

Form에서 렌더링을 방지하려면 어떻게 해야할까요? React.memo로 컴포넌트를 메모이제이션하는 방법이 있습니다.

const LogInForm = React.memo((props) => {
  return ( ... );
});

위와 같이 컴포넌트를 React.memo로 한번 감싸주면 해당 컴포넌트는 메모이제이션됩니다. 메모된 LogInForm 컴포넌트는 props가 변하지 않으면 렌더링되지 않습니다.

useCallback

이 다음엔 props를 확인해야 합니다. props가 바뀌면 리렌더링되기 때문에 props 중에 불필요하게 바뀌는 부분이 있는지 확인해야 합니다.

실제로 React.memo를 적용해도 계속 렌더링이 일어나는데, Form에 props로 전달되는 콜백함수가 LogInContainer가 렌더링될 때마다 계속 새로 생성되기 때문입니다.

이 경우에 useCallback을 사용하여 콜백함수를 메모이제이션할 수 있습니다.

const onSuccessLogInWithPassword = useCallback((authToken: string) => {
  setAuthToken(authToken);
  openModal();
}, []);

위와같이 함수를 useCallback의 첫 번째 인자로 넘겨주고, 두 번째 인자로 deps 배열을 넘겨주면 deps에 있는 값이 바뀔 때만 함수가 새로 생성됩니다.


성능 개선 평가

이제 성능이 얼마나 개선되었는지 측정해보겠습니다.

Dec-27-2020 21-31-29

스크린샷 2020-12-27 오후 6 10 44

Form 안쪽 부분은 렌더링되지 않는 것을 볼 수 있고, Profiler에서도 Form 부분은 회색부분으로 렌더링되지 않은 것을 볼 수 있습니다.

렌더링 시간은 총 3.5ms 정도로 2.4ms정도 줄인 것을 확인할 수 있습니다.


마무리

  1. 렌더링 시간을 더 줄일 수 있지 않을까 해서 Modal 내부의 다른 부분도 memo를 적용해봤는데 큰 차이 없었습니다.
    아마도 렌더링하는 시간이 아주 짧아서 메모를 적용하지 않았을 때 컴포넌트를 렌더링하는 시간과 메모를 적용했을 때 렌더링을 할지 판단하는 시간이 비슷하지 않을까 개인적으로 추측해봅니다..

  2. 위에서 해본 상황은 10ms 이내로 매우 짧아서 최적화를 하나 안하나 차이를 못 느끼는 수준이었습니다. 그래도 직접 성능 개선을 시도했다는 것에 의미를 두고 있습니다.

  3. 성능을 개선하는 방법도 중요하지만 성능을 측정하는 것이 더 중요하다고 느꼈습니다. 무턱대고 useMemo, useCallback과 같은 훅을 적용하는 것보다, 어떤 부분이 느린지 정확히 판단하고성능을 개선한 뒤에 얼마나 개선됐는지 다시 측정해서 효과가 있는지 보는 게 정말 중요한 것 같습니다.

profile
Engineer

0개의 댓글