[React] React.memo 렌더링 성능 실험

이상엽·2024년 9월 18일

배경

우테코에서 진행한 성능 개선하기 미션 중
검색 결과 > 추가 로드시 추가되는 결과에 대해서만 화면 업데이트가 새로 일어나야 한다라는 미션이 있었다.

해당 그림과 같이 load more 버튼을 클릭하면 서버 요청을 통해 추가 GIF 데이터를 불러와 렌더링하는 페이지인데, 기존에 있던 이미지는 화면 업데이트가 일어나지 않고 새로 추가되는 이미지만 화면 업데이트가 일어나게 해야 한다.

이때 GIF_카드_컴포넌트는 동일한 key 값에 동일한 props를 가지고 있기에 React에서 DOM 업데이트를 하지 않을 것이기에 성능의 문제가 없을 것으로 생각하여 성능에 문제가 없다고 생각했었다.

메모이제이션

우선 해당 미션의 정답은 React.memo를 이용하여 GIF_카드_컴포넌트를 메모이제이션 하는 것이다.

하지만 위에서 말한 것처럼 동일한 key, props를 이용하는 경우 동일한 컴포넌트이기에 실제 DOM에는 반영이 안 되어 성능의 차이가 없지 않을까? 생각했고 궁금증을 해결하기 위해 메모이제이션 실험을 해보았다.

실험

해당 궁금증을 해결하기 위해 가장 좋은 방법은 실험이라 생각하여 개발자 도구의 performance 탭을 이용하여 렌더링 성능 측정을 진행하였다.

실험 방법

측정 도구 : 개발자 도구의 performance 탭을 이용하여 React.memo를 사용했을 때, 안 했을 때 렌더링 성능 측정

측정 방법 : 렌더링할 컴포넌트가 많아야 유의미한 차이가 있기에 검색창에 otter를 검색한 후 마지막 페이지까지 load more 버튼을 클릭하고 렌더링에 걸린 시간 비교

React.memo 적용 전

우선 profile의 결과 GIF_카드_컴포넌트의 개수가 많이 없을 때 렌더링에 걸린 시간은 1.6ms가 걸렸다.

하지만 아래 이미지와 같이 GIF_카드_컴포넌트의 개수가 많은 경우 각각 컴포넌트마다 연산의 시간이 걸려 총 렌더링 시간이 5.9ms 소요되었다.

React.memo 적용 후

React.memo로 메모이제이션을 적용했을 때 결과를 본다면 GIF_카드_컴포넌트의 개수가 많은 경우에도 렌더링 시간이 1.1ms 메모이제이션을 적용했을 때 성능의 이점을 확인할 수 있었다.

실험 결과

위아래 이미지를 비교해 보면 memo를 적용하기 전에는 SearchResult 하위의 각각의 컴포넌트들은 모두 메인 스레드에서 연산이 일어나 시간 소요가 되었으며, memo를 적용했을 때는 결과를 메모리에서 가져왔기에 어두운색으로 빗금이 쳐져 있고 연산의 시간 소요가 적었음을 확인할 수 있다.

그래서 실제로 렌더링에 걸린 시간이 5.9ms -> 1.1ms로 유의미한 차이를 확인할 수 있었다.

결론

그러면 기존 GIF_카드_컴포넌트는 변하지 않아 실제 DOM에 변경 사항이 없을 것인데 왜 이런 결과를 확인할 수 있었을까?

우선 실제 DOM에 변경 사항이 없다고 판단한 이유

우선 GIF_카드_컴포넌트가 변경되어 실제 DOM에 변경 사항이 있었다면 load more 버튼 클릭 시 재생되고 있던 GIF는 다시 처음부터 영상이 실행되어야 하는데,

새로운 GIF를 불러와도 현재 재생 중인 프레임을 유지하고 있기에 기존에 있던 GIF_카드_컴포넌트는 실제 DOM에서는 변경이 없음을 알 수 있다.

메모이제이션을 적용하지 않은 경우

메모이제이션을 적용하지 않은 경우에 React에서 key, props 등의 값을 이용하여 가상 DOM에 GIF_카드_컴포넌트를 렌더한 다음, 가상 DOM과 실제 DOM을 비교하여 동일한지 확인하여 동일하다면 Commit을 하지 않게 된다.

그러면 실제 DOM에 아무런 변경이 없지만 가상 DOM의 연산이 일어나 오버헤드를 발생시키기에 GIF_카드_컴포넌트의 개수가 적으면 상관없지만 많을수록 성능의 문제가 있음을 알 수 있다.

메모이제이션을 적용한 경우

인자로 받은 key, props 값을 가상 DOM의 key, props를 비교하여 동일하면 아무런 작업을 취하지 않는다. (변경 사항이 없기 때문)

그렇기에 가상 DOM에 불필요하게 GIF_카드_컴포넌트를 렌더하여 실제 DOM과 비교하는 불필요한 행위를 하지 않기에 메인 스레드의 작업을 줄여주어 성능이 최적화될 수 있다.

한 줄 요약

key, props가 동일하여 실제 DOM의 변경이 일어나지 않아도 React.memo를 이용하여 메인 스레드의 할 일을 줄여 렌더링 성능을 개선할 수 있다.

미션을 진행한 PR 링크

0개의 댓글