-
Notifications
You must be signed in to change notification settings - Fork 5
React 성능 최적화
리액트에서 불필요한 렌더링을 최소화하여 성능을 최적화할 수 있습니다. 성능 최적화를 시도해보면서 공부해보겠습니다.
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
페이스북에서 만든 리액트 디버깅 툴입니다. 컴포넌트 트리를 볼 수도 있고, 프로파일링 기능도 제공하여 성능 최적화 시 많은 도움을 받을 수 있습니다.
일단 성능을 개선하려면 지금 성능이 좋은지, 안좋은지 판단할 수 있어야 합니다. 리액트에서 성능이 안좋다는 것은 무슨 말일까요?
대부분의 경우 화면을 렌더링하는데 많은 시간이 걸리거나 불필요한 렌더링이 발생하는 경우에 성능이 좋지 않다고 판단하는 것 같습니다.
그렇다면 React DevTools로 성능이 저하되는 부분을 찾아봅시다.
위의 이미지처럼 React DevTools에는 렌더링되는 부분을 시각적으로 표현해주는 기능이 있습니다. 반짝이는 부분이 해당 컴포넌트가 렌더링되었다는 의미입니다.
위 상황은 Form 위에 Modal을 띄운 상황이고, Modal에 값을 입력할 때 아래 겹쳐져있는 Form에서도 렌더링이 일어난다는 것을 알 수 있습니다.
React DevTools의 Profiler 기능으로 렌더링 과정을 더 자세하게 측정할 수 있습니다.
하나의 값을 입력할 때의 과정을 측정해보니 총 5.9ms 정도 걸렸고 Form을 렌더링하는데 2.1ms, Modal을 렌더링하는데 3.7ms 정도 걸린것으로 보입니다.
왜 이런 일이 발생할까요? Modal과 Form의 부모 컴포넌트인 LogInContainer에서 상태를 가지고 있고, Modal에서 값을 입력하면 그 상태가 변경되어서 Modal과 Form 둘 다 리렌더링되기 때문입니다.
Form에서 렌더링을 방지하려면 어떻게 해야할까요? React.memo
로 컴포넌트를 메모이제이션하는 방법이 있습니다.
const LogInForm = React.memo((props) => {
return ( ... );
});
위와 같이 컴포넌트를 React.memo
로 한번 감싸주면 해당 컴포넌트는 메모이제이션됩니다. 메모된 LogInForm 컴포넌트는 props가 변하지 않으면 렌더링되지 않습니다.
이 다음엔 props를 확인해야 합니다. props가 바뀌면 리렌더링되기 때문에 props 중에 불필요하게 바뀌는 부분이 있는지 확인해야 합니다.
실제로 React.memo
를 적용해도 계속 렌더링이 일어나는데, Form에 props로 전달되는 콜백함수가 LogInContainer가 렌더링될 때마다 계속 새로 생성되기 때문입니다.
이 경우에 useCallback
을 사용하여 콜백함수를 메모이제이션할 수 있습니다.
const onSuccessLogInWithPassword = useCallback((authToken: string) => {
setAuthToken(authToken);
openModal();
}, []);
위와같이 함수를 useCallback
의 첫 번째 인자로 넘겨주고, 두 번째 인자로 deps 배열을 넘겨주면 deps에 있는 값이 바뀔 때만 함수가 새로 생성됩니다.
이제 성능이 얼마나 개선되었는지 측정해보겠습니다.
Form 안쪽 부분은 렌더링되지 않는 것을 볼 수 있고, Profiler에서도 Form 부분은 회색부분으로 렌더링되지 않은 것을 볼 수 있습니다.
렌더링 시간은 총 3.5ms 정도로 2.4ms정도 줄인 것을 확인할 수 있습니다.
-
렌더링 시간을 더 줄일 수 있지 않을까 해서 Modal 내부의 다른 부분도 memo를 적용해봤는데 큰 차이 없었습니다. 아마도 렌더링하는 시간이 아주 짧아서 메모를 적용하지 않았을 때 컴포넌트를 렌더링하는 시간과 메모를 적용했을 때 렌더링을 할지 판단하는 시간이 비슷하지 않을까 개인적으로 추측해봅니다..
-
위에서 해본 상황은 10ms 이내로 매우 짧아서 최적화를 하나 안하나 차이를 못 느끼는 수준이었습니다. 그래도 직접 성능 개선을 시도했다는 것에 의미를 두고 있습니다.
-
성능을 개선하는 방법도 중요하지만 성능을 측정하는 것이 더 중요하다고 느꼈습니다. 무턱대고
useMemo
,useCallback
과 같은 훅을 적용하는 것보다, 어떤 부분이 느린지 정확히 판단하고성능을 개선한 뒤에 얼마나 개선됐는지 다시 측정해서 효과가 있는지 보는 게 정말 중요한 것 같습니다.
© Boostcamp