Docs
GUIDES & CONCEPTS
Render Optimizations

Render Optimizations

React Query는 컴포넌트가 실제로 필요할 때만 다시 렌더링되도록 보장하기 위해 여러 가지 최적화를 자동으로 적용합니다. 이러한 최적화는 다음과 같은 방법으로 수행됩니다:

structural Sharing

React Query는 "구조적 공유"라는 기술을 사용하여 가능한 한 많은 참조를 유지합니다. 데이터가 네트워크를 통해 가져와질 때, 일반적으로 JSON 응답을 파싱함으로써 완전히 새로운 참조를 얻습니다. 그러나 React Query는 데이터에 변화가 없으면 원래의 참조를 유지합니다. 부분적인 변경이 있는 경우, React Query는 변경되지 않은 부분을 유지하고 변경된 부분만 교체합니다.

주의: 이 최적화는 queryFn이 JSON 호환 데이터만 반환하는 경우에만 작동합니다. 글로벌 또는 쿼리별로 structuralSharing: false를 설정하여 이 최적화를 끌 수 있으며, 함수로 직접 구조적 공유를 구현할 수도 있습니다.

referential Identity

useQuery, useInfiniteQuery, useMutation에서 반환된 최상위 객체와 useQueries에서 반환된 배열은 참조적으로 안정적이지 않습니다. 매 렌더링 시마다 새로운 참조가 생성됩니다. 그러나 이러한 훅에서 반환된 data 속성은 가능한 한 안정적입니다.

tracked properties

React Query는 useQuery에서 반환된 속성 중 실제로 "사용되는" 속성만으로 렌더링을 트리거합니다. 이는 커스텀 게터 (opens in a new tab)를 사용하여 수행됩니다. 이로 인해 isFetching 또는 isStale과 같이 자주 변경될 수 있지만 컴포넌트에서 사용되지 않는 속성 때문에 불필요한 렌더링이 줄어듭니다.

이 기능은 글로벌 또는 쿼리별로 notifyOnChangeProps를 수동으로 설정하여 사용자 정의할 수 있습니다. 이 기능을 끄고 싶다면 notifyOnChangeProps: 'all'로 설정할 수 있습니다.

주의: 커스텀 게터는 속성에 접근할 때 호출됩니다. 즉, 구조 분해 할당을 사용하거나 직접 접근할 때 호출됩니다. 객체의 나머지 구조 분해 할당을 사용하면 이 최적화가 비활성화됩니다. 이 함정을 방지하기 위해 lint 규칙을 제공하고 있습니다.

select

select 옵션을 사용하여 컴포넌트가 구독할 데이터의 하위 집합을 선택할 수 있습니다. 이는 데이터 변환을 최적화하거나 불필요한 렌더링을 방지하는 데 유용합니다.

export const useTodos = (select) => {
  return useQuery({
    queryKey: ["todos"],
    queryFn: fetchTodos,
    select,
  });
};
 
export const useTodoCount = () => {
  return useTodos((data) => data.length);
};

useTodoCount 사용자 정의 훅을 사용하는 컴포넌트는 todos의 길이가 변경될 때만 다시 렌더링됩니다. todos의 이름이 변경되더라도 다시 렌더링되지 않습니다.

memoization

select 함수는 다음 두 가지 조건 중 하나가 만족될 때만 다시 실행됩니다:

  • select 함수 자체가 참조적으로 변경된 경우
  • data가 변경된 경우

즉, 위에서 보여준 인라인 select 함수는 매 렌더링 시마다 실행됩니다. 이를 피하기 위해 useCallback으로 select 함수를 감싸거나, 종속성이 없는 안정적인 함수 참조로 추출할 수 있습니다:

// useCallback으로 감싸기
export const useTodoCount = () => {
  return useTodos(useCallback((data) => data.length, []));
};
// 안정적인 함수 참조로 추출하기
const selectTodoCount = (data) => data.length;
 
export const useTodoCount = () => {
  return useTodos(selectTodoCount);
};

Further Reading

이러한 주제에 대한 자세한 가이드를 보려면, React Query 렌더링 최적화 커뮤니티 리소스를 읽어보세요.