Skip to content

불필요한 리렌더링 개선

박경희 edited this page Feb 18, 2025 · 5 revisions

문제 정의 및 리팩토링 목표

페이지 리스트 토글 버튼 클릭 시, 페이지 리스트가 펼쳐지면서 관련된 컴포넌트만 렌더링되는 것이 아니라 웹사이트의 모든 컴포넌트가 불필요하게 렌더링되는 문제가 발생했다.

React DevTools의 Profiler를 활용한 분석 결과, 페이지 리스트 컴포넌트가 렌더링된 후 최상위 컴포넌트인 App 컴포넌트가 추가로 렌더링되는 현상이 확인되었다.

image

image

이러한 추가적인 렌더링은 성능 저하를 유발하며, 사용자 경험(UX)에 부정적인 영향을 미칠 가능성이 있다. 그래서 페이지 리스트 토글 시 해당 컴포넌트만 렌더링되도록 최적화하여 성능과 UX를 개선하고자 한다.

문제 해결 과정

Tools 컴포넌트에서 발생하는 렌더링 문제를 소거법으로 추적한 결과, useCurrentWorkspace 훅의 동작이 원인으로 밝혀졌다. Tools는 페이지 목록 상단에 있는 버튼 컴포넌트로, 새로운 페이지를 생성할 때 현재 워크스페이스 정보를 필요로 한다. 이 과정에서 useCurrentWorkspace는 내부적으로 사용자의 snowflakeId를 참조한다. 이 과정에서 useCurrentWorkspace는 사용자의 snowflakeId 값을 참조하는데, 해당 값의 변화가 컴포넌트 재렌더링의 원인이 되었다. 로그인 여부에 따라 렌더링 결과가 달라지는 것도 확인되었다.

  • 비로그인
default.mp4
  • 로그인
default.mp4

로그인되지 않은 상태에서는 리스트 외 다른 컴포넌트들이 렌더링되지만, 로그인된 상태에서는 해당 컴포넌트들이 렌더링되지 않는 차이를 보였다. 이때 로그인 여부를 결정하는 기존 로직은 useGetUser 훅을 통해 snowflakeId를 반환받거나, 403 오류가 발생하면 "null" 값을 설정하는 방식이었다. 하지만 403 오류는 캐싱되지 않아, 이를 참조하는 컴포넌트들이 반복적으로 쿼리를 호출하며 렌더링 문제를 유발했다.

const { data: user, isError } = useGetUser();

const snowflakeId = isError ? "null" : (user?.snowflakeId ?? "null");

문제를 해결하기 위해 로그인 상태를 반환하는 useGetUserStatus 훅을 추가하고, 이를 활용해 snowflakeId를 관리하도록 개선했다. 개선된 코드는 loggedIn 값을 기준으로 snowflakeId를 설정하며, 로그인 상태가 true일 때만 사용자 정보를 참조하고 그렇지 않으면 "null" 값을 반환한다. 이를 통해 403 오류 상태를 직접 참조하지 않으면서도 캐싱이 가능해져, 불필요한 렌더링을 방지하고 효율적인 데이터 관리를 달성했다.

const { data: loggedIn } = useGetUserStatus();
const { data: user } = useGetUser();

const snowflakeId = loggedIn ? "null" : (user?.snowflakeId ?? "null");

결과

개선 작업 이후에는 useCurrentWorkspace 훅에 의존하는 컴포넌트들의 불필요한 렌더링이 감소하고 API 호출이 최적화되었다. 페이지 리스트를 펼쳤을 때 추가적인 렌더링이 발생하지 않도록 개선하였으며, React Profiler를 확인해본 결과 App이 렌더링되지 않아 렌더링 시간을 10.5ms 감소할 수 있었다.

추가적으로 공유 기능, 워스크스페이스 리스트 기능에서도 동일한 문제가 발생하였는데 위의 문제 해결 후, 함께 해결되었다.

image

Clone this wiki locally