원문 : https://medium.com/inato/prevent-re-renders-in-your-react-app-using-react-profiler-93c492110e30
최근에 저는 리액트 앱에서 페이지 성능 개선을 노력하고 있었고, 불필요한 리렌더링이 중요한 문제라는 것을 금방 알게 되었습니다. 도움을 받을 수 있는 플러그인을 조사하다 우연히 리액트 개발자 도구 프로파일러를 알게 되었습니다.
이 플러그인은 리액트 애플리케이션의 성능 병목 현상을 식별하기 위해 리액트의 실험적인 프로파일러 API를 사용하여 렌더링 되는 각 구성 요소에 대한 타이밍 정보를 수집합니다. (출처)
게다가 이 플러그인의 숨겨진 옵션으로, 컴포넌트가 렌더링 된 이유를 알려주는 기능이 있다는 것을 알게 되었습니다. 저는 이 기능이 매우 유용하는 것을 깨닫고 사용법을 공유하기 위해 이 글을 쓰기로 결심했습니다!
먼저 개발자 도구에서 이 옵션을 활성화하는 방법은 다음과 같습니다.
이제 오늘의 목표를 확인하고 완료로 변경할 수 있는 간단한 애플리케이션으로 예를 들어 보겠습니다. 리액트 프로파일러를 사용하여 프로파일을 생성하고 "Set as done" 버튼을 클릭하여 프로그램에서 어떤 일이 일어나는지 확인해 보겠습니다.
"막대 색상은 컴포넌트(및 자식 요소)가 선택한 커밋에서 렌더링하는 데 걸린 시간을 나타냅니다. 노란색 컴포넌트는 시간이 더 오래 걸리고 파란색 컴포넌트는 조금 덜 걸리고 회색 컴포넌트는 이 커밋 중에 렌더링되지 않았습니다." (출처)
우리는 모든 "Goal" 하위 컴포넌트가 다시 렌더링되었음을 알 수 있습니다. 이상적인 상황은 "Read 30 min" 목표만 업데이트했기 때문에 다른 Goal
컴포넌트는 렌더링 되지 않고 해당 Goal
컴포넌트만 다시 렌더링되는 것입니다.
이 문제를 어떻게 해결할 수 있을까요? 바로 여기에서 앞서 선택했던 리액트 프로파일러 옵션을 활용해 컴포넌트가 렌더링된 이유를 알아볼 수 있습니다. 프로파일링 데이터에 첫 번째 Goal 컴포넌트를 표시해 보겠습니다.
확인해보니 setAsDone
프로퍼티가 변경된 것이 문제였습니다. 이 문제를 빠르게 해결해 보겠습니다.
수정한 덕분에 Goals
컴포넌트 각각의 렌더에서 setAsDone
으로 설정된 함수는 변경되지 않습니다. 하지만 안타깝게도, 다른 Goal
컴포넌트의 리렌더링 방지를 위한 대응으로는 충분하지 않습니다. 프로파일링 데이터를 통해 알 수 있는 내용은 다음과 같습니다.
Goals
컴포넌트가 다시 렌더링 되었기 때문에 Goal
컴포넌트도 다시 렌더링 되었습니다. 그리고 Goals
컴포넌트는 "Hook 1 changed" 때문에 다시 렌더링 되었는데, 그다지 명확하지는 않죠?
"Hook 1"에 대해 더 알아보기 위해 "Components" 탭으로 전환하면 개발자 도구에 올바른 컴포넌트가 표시됩니다.
이제 우리는 "Hook 1 changed"가 실제론 "goalsReached
상태가 변경됨"을 의미한다는 것을 알 수 있습니다. 이 경우에는 goalsReached
상태에 "30분 읽기"라는 목표를 추가한 것이 해당됩니다.
이런 특수한 경우에는 React.memo
를 사용하여 문제를 해결할 수 있습니다. (물론 모든 경우에 최선의 해결책은 아닐 수 있지만 이 예제에서는 간단히 설명하겠습니다.)
"컴포넌트가 동일한 속성을 사용하여 동일한 결과를 렌더링 하는 경우에는, 이를
React.memo
호출로 래핑 해 결과를 메모하여 성능을 향상시킬 수 있습니다. 이는 React가 컴포넌트 렌더링을 건너뛰고 마지막으로 렌더링 된 결과를 재사용한다는 것을 의미합니다." (출처)
한 번 더 앱을 프로파일링 해 보겠습니다.
이제 정확히 Goal
컴포넌트만 다시 렌더링 되고 나머지 컴포넌트는 렌더링 되지 않는 것을 볼 수 있습니다 🥳
이러한 일련의 과정은 리액트 앱 성능을 향상시키는데 도움이 될 것입니다! 자유롭게 질문하거나 리액트 프로파일러에 대한 경험과 노하우를 공유해주세요!
디버깅할 때 한 번 사용해 봐야 겠네요. 좋은 글 감사합니다~