React DevTools 프로파일러를 활용하여 컴포넌트 렌더링 성능 개선하기

김가희·2024년 5월 9일
0

성능 개선 전

나는 주로 input으로 인한 리렌더링이 많을 거라고 예상하였고 폼 위주로 분석해 보았다.
위 스크린샷은 프로필 편집 페이지에서 닉네임 인풋에 계속 타이핑하고 수정하기 버튼까지 누르는 걸 레코드 한 결과다.



분석 포인트

  1. 리렌더링된 컴포넌트: FormProvider, RadioGroup, RovingFocusGroup, Slot 등 여러 컴포넌트가 리렌더링되고 있다. 이 중 FormProvider와 관련된 컴포넌트들이 자주 보이는데, 이는 폼 상태 관리 로직이 입력 변화에 민감하게 반응하고 있음을 나타낸다.
  2. 렌더링 시간: 각 컴포넌트의 렌더링 시간이 일반적으로 짧아 보이지만, 많은 수의 컴포넌트가 반복적으로 리렌더링되고 있어 총 렌더링 비용이 증가하고 있다.
  3. 리렌더링 원인: 'Rendered at' 타임라인을 보면, 닉네임 입력 필드에서 발생하는 상태 변경이 다른 많은 컴포넌트에 영향을 주고 있다. 이는 상태 관리 구조를 재검토해 볼 필요가 있음을 시사한다.

• React DevTools의 "왜 리렌더링되었나요?" 기능을 활용하여 각 컴포넌트의 리렌더링 원인을 정확히 파악할 수 있다. 이 도구는 컴포넌트의 props 또는 state가 변경될 때 그 변경 사항과 함께 리렌더링된 이유를 상세히 알려 준다.

개선 방안

  1. useCallback 사용: useCallback은 함수가 필요할 때만 다시 생성되도록 캐싱한다.
    입력 필드의 값이 변경될 때 실행되는 이벤트 핸들러 함수는 useCallback으로 감싸서, 입력 값이 변경될 때만 함수가 재생성되도록 하였다.
    ```tsx
    const onSubmit = useCallback(
      (values: ProfileFormValues) => {
        updateProfile(user?.uid as string, values)
          .then(result => {
            if (result.success) {
              openAlert('프로필이 수정되었습니다.', '');
              setUser(result.user!);
            } else {
              openAlert('오류가 발생했습니다.', result.error as string);
            }
          })
          .catch(error => {
            openAlert('오류가 발생했습니다.', error);
          });
      },
      [user?.uid, setUser, openAlert],
    );
    ```
  2. React.memo 사용: React.memo는 컴포넌트가 동일한 props로 렌더링될 때 이전 렌더링 결과를 재사용할 수 있도록 해 준다. 이 기능을 사용하여 폼과 같이 빈번히 업데이트되는 컴포넌트의 불필요한 리렌더링을 방지할 수 있다.
    닉네임 인풋의 값을 변경할 때 다른 인풋들도 계속 리렌더링 되었기에 React.memo를 적용해 주었다.
    ```tsx
    function ProfileEmailInput({ loginType, email }: ProfileEmailInputProps) {
      return (
        <div className='flex flex-col space-y-2'>
        {/* ... 생략 */}
        </div>
      );
    }
    
    export default React.memo(ProfileEmailInput);
    ```


성능 개선 후

개선 방안을 실행한 후 다시 프로파일링 해 본 결과다. 전에 비해 리렌더링 되는 컴포넌트가 확실히 줄어든 것을 확인할 수 있다.

현재 shadcn/ui의 Form 컴포넌트를 활용하고 있는데, 그 컴포넌트에서 Context를 활용하여 값을 관리하고 있어서 ProfileForm 컴포넌트와 ContextProvider가 계속 리렌더링 되고 있다. 이것을 해결해 볼 방안도 찾아봐야겠다.



참고: https://heycoding.tistory.com/135

0개의 댓글