React Query의 캐시타임(Cache Time)과 스테일타임(Stale Time), 포커스 속성에 대한 이해

Eddy·2023년 5월 26일
1

React

목록 보기
21/21

React Query의 캐시타임(Cache Time)과 스테일타임(Stale Time), 포커스 속성에 대한 이해

React Query는 클라이언트 상태 관리와 비동기 데이터 처리를 효율적으로 처리할 수 있는 도구로, 특히 데이터를 캐싱하고 적절한 시점에 갱신하는 기능이 강력합니다. 이 글에서는 캐시타임(Cache Time), 스테일타임(Stale Time), 포커스 속성(refetchOnWindowFocus)에 대해 깊이 이해하고, 이를 활용하여 최적의 데이터 페칭 로직을 구현하는 방법을 소개합니다.

1. 캐시타임(Cache Time)

캐시타임은 React Query가 데이터를 메모리에 유지하는 기간을 의미합니다. 데이터가 더 이상 화면에서 사용되지 않더라도, 지정된 캐시타임 동안 메모리에 남아 있어 다시 요청하지 않고 재사용할 수 있습니다.

  • 기본값: 5분 (300000ms)
  • 설정 방법: cacheTime 옵션을 통해 설정할 수 있습니다.
useQuery('key', fetchFunction, {
  cacheTime: 1000 * 60 * 10, // 10분 동안 캐시 유지
});
  • 작동 방식:
  1. 컴포넌트가 언마운트되면 React Query는 데이터를 메모리에 유지합니다.
  2. 설정된 시간이 지나면 캐시가 삭제됩니다.
  3. 같은 키로 데이터를 요청하면, 캐시가 존재하면 새 요청 없이 데이터를 반환합니다.
  • 사용 시점:
    • 사용 빈도가 낮은 데이터인 경우 캐시타임을 길게 설정하여 불필요한 서버 요청을 줄입니다.
    • 사용자 전환이 많은 페이지에서 데이터 로드를 최적화하고 싶을 때 활용합니다.

2. 스테일타임(Stale Time)

스테일타임은 데이터가 "최신 데이터"로 간주되는 시간을 의미합니다. 이 시간이 지나면 데이터가 "stale(오래된)" 상태로 간주되고, 다음 액션(리패칭 등) 시 새 데이터를 가져옵니다.

  • 기본값: 0ms (항상 stale로 간주)
  • 설정 방법: staleTime 옵션을 통해 설정합니다.

useQuery('key', fetchFunction, {
  staleTime: 1000 * 60 * 5, // 5분 동안 데이터를 최신으로 간주
});
  • 작동 방식:
  1. 데이터를 요청한 후 설정된 기간 동안 데이터를 최신으로 간주합니다.
  2. 최신 상태에서는 추가적인 데이터 페칭이 발생하지 않습니다.
  3. 스테일 상태가 되면, 새로고침, 화면 포커스 시점에서 리패칭이 트리거됩니다.
  • 사용 시점:
    • 자주 변경되지 않는 데이터(예: 카테고리 목록, 고정된 설정 데이터)에 유용합니다.
    • 실시간성이 중요하지 않은 데이터에는 긴 staleTime을 설정해 성능을 최적화합니다.

3. 포커스 속성(refetchOnWindowFocus)

포커스 속성은 브라우저 창(탭)이 다시 포커스될 때 데이터를 리패칭할지 여부를 제어합니다.

  • 기본값: true (포커스 시 리패칭 활성화)
  • 설정 방법: refetchOnWindowFocus 옵션을 통해 설정합니다.
useQuery('key', fetchFunction, {
  refetchOnWindowFocus: false, // 포커스 시 리패칭 비활성화
});
  • 작동 방식:
  1. 사용자가 브라우저 탭을 전환하고 다시 돌아오면, React Query는 자동으로 데이터를 리패칭합니다.
  2. 데이터를 "최신 상태"로 유지하고 싶을 때 유용합니다.
  • 사용 시점:
    • true 설정:
      • 실시간성이 중요한 데이터(예: 주식 시세, 대시보드 데이터).
    • false 설정:
      • 성능이 중요하거나, 데이터가 자주 변경되지 않는 경우.

4. 예제: 캐시타임, 스테일타임, 포커스 속성 활용

import { useQuery } from 'react-query';

const fetchUserData = async () => {
  const response = await fetch('/api/user');
  return response.json();
};

const UserProfile = () => {
  const { data, isLoading, isError } = useQuery('user', fetchUserData, {
    cacheTime: 1000 * 60 * 10, // 10분 동안 캐시 유지
    staleTime: 1000 * 60 * 5, // 5분 동안 데이터를 최신 상태로 간주
    refetchOnWindowFocus: true, // 포커스 시 리패칭 활성화
  });

  if (isLoading) return <p>Loading...</p>;
  if (isError) return <p>Error loading data</p>;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.email}</p>
    </div>
  );
};

export default UserProfile;

5. 캐시타임과 스테일타임의 차이점

속성캐시타임 (cacheTime)스테일타임 (staleTime)
의미데이터를 메모리에 유지하는 시간데이터를 최신으로 간주하는 시간
기본값5분 (300000ms)0ms
주요 사용 시점페이지 전환 시 캐시를 유지하고 서버 요청을 줄이고 싶을 때데이터가 자주 갱신되지 않고, 실시간성이 중요하지 않을 때
영향데이터가 캐시에 있는 동안 새 요청 없이 반환스테일 상태가 되기 전까지 추가 패칭을 수행하지 않음

6. 캐시타임과 스테일타임 설정 시 주의점

  • 긴 캐시타임과 스테일타임 설정의 문제점:
    • 데이터가 오래된 상태로 유지될 위험이 있습니다.
    • 특히 실시간성이 중요한 데이터에서는 긴 설정은 피해야 합니다.
  • 짧은 캐시타임과 스테일타임 설정의 문제점:
    • 서버로의 요청이 지나치게 많아져 성능 저하 및 API 비용 증가 가능성이 있습니다.
  • 적정 설정 기준:
    • 캐시타임: 데이터 사용 빈도에 따라 설정. 자주 접근하지 않는 데이터는 긴 캐시타임.
    • 스테일타임: 데이터 갱신 주기와 사용자 경험에 따라 설정.

7. 정리

React Query의 캐시타임, 스테일타임, 포커스 속성을 적절히 활용하면 데이터 페칭 로직을 효율적으로 관리할 수 있습니다.

  • 캐시타임으로 불필요한 데이터 삭제를 방지하고 성능을 최적화합니다.
  • 스테일타임을 설정해 적절한 시점에 데이터 갱신을 유도합니다.
  • 포커스 속성을 활용해 실시간성과 성능 요구에 맞는 경험을 제공합니다.

8. 알면 좋은 추가 내용

1.초기 데이터 Prefetching과 연계

캐시타임과 스테일타임은 초기 데이터를 프리패칭(prefetch)한 후에도 영향을 미칩니다.

  • 초기 데이터 프리패칭과 staleTime:
    • 초기 데이터가 최신으로 간주되도록, staleTime을 설정합니다.
    • 프리패칭 후 불필요한 네트워크 요청을 줄이는 데 유용합니다.
// Prefetch example
import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from 'react-query';

const queryClient = new QueryClient();

queryClient.prefetchQuery('user', fetchUserData, {
  staleTime: 1000 * 60 * 10, // 10분 동안 최신 데이터로 간주
});

2.refetchOnWindowFocus와 네트워크 상태 관리

  • refetchOnWindowFocus는 네트워크 상태와 함께 사용할 수 있습니다.
  • React Query는 navigator.onLine 상태를 감지하여 오프라인 상태에서는 리패칭을 중지하고, 온라인 상태로 전환되면 자동으로 리패칭합니다.
useQuery('key', fetchFunction, {
  refetchOnWindowFocus: true,
  refetchOnReconnect: true, // 네트워크 재연결 시 리패칭
});
  • 활용 사례:
    • 온라인 쇼핑몰: 사용자가 네트워크 재연결 시 최신 재고 정보를 확인.
    • 대시보드: 포커스 및 네트워크 복구 시 실시간 데이터를 갱신.

3. queryKey의 중요성과 동적 데이터 처리

캐싱 전략은 queryKey와 밀접하게 연관됩니다. 잘못된 queryKey 설계는 캐싱의 장점을 무효화할 수 있습니다.

  • queryKey의 설계:
    • 데이터가 고유한 쿼리 키를 가져야만 캐시가 적절히 작동합니다.
    • 동적 데이터(예: 사용자 ID, 페이지 번호)에 대해 키를 유니크하게 설정해야 합니다.
useQuery(['user', userId], fetchUserData);
useQuery(['posts', page], fetchPosts);
  • queryKey와 캐시 활용:
    • 동일한 queryKey는 동일한 캐시 데이터를 재활용합니다.
    • 동적으로 생성된 키를 활용해 데이터 갱신과 캐싱의 유연성을 극대화합니다.

4.React Query Devtools를 활용한 상태 확인

React Query는 개발 중 데이터의 캐싱 상태, 스테일 상태 등을 실시간으로 확인할 수 있는 Devtools를 제공합니다.

  • 설치: npm install @tanstack/react-query-devtools
  • 사용:
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <YourApp />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}
  • 활용 사례:
    • 각 쿼리의 캐시 상태, 스테일 여부, 리패칭 기록을 확인.
    • cacheTime, staleTime 설정이 적절한지 실시간으로 점검.

5. Polling (자동 갱신)

React Query는 일정 간격으로 데이터를 자동 갱신할 수 있는 기능도 제공합니다.

  • Polling 설정:
useQuery('key', fetchFunction, {
  refetchInterval: 1000 * 60, // 1분마다 데이터 갱신
  refetchIntervalInBackground: true, // 비활성 상태에서도 실행
});
  • 활용 사례:
    • 주식, 환율 데이터와 같이 실시간 갱신이 필요한 서비스.
    • 유저의 페이지 상태와 무관하게 최신 데이터를 유지.

6. 배치된 요청 처리

React Query는 동일한 컴포넌트 내 여러 쿼리 요청을 배치(batch) 처리하여 네트워크 성능을 향상할 수 있습니다.

  • 배치 옵션 활성화:
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      useErrorBoundary: true,
      retry: 1,
    },
  },
});

useErrorBoundary: true: 에러가 발생하면 컴포넌트 내에서 처리하지 않고, ErrorBoundary 컴포넌트에 에러를 전달합니다.
retry: 1: 쿼리 요청 실패 시 최대 1번 재시도합니다.

  • 배치 처리의 장점:
    • 네트워크 부하 감소: 요청을 묶어 보내기 때문에 불필요한 요청을 줄일 수 있습니다.
    • 성능 최적화: 여러 쿼리 결과를 한 번에 반환하여 리렌더링 빈도를 낮춥니다.
  • 활용 사례:
    • 주식, 환율 데이터와 같이 실시간 갱신이 필요한 서비스.
    • 유저의 페이지 상태와 무관하게 최신 데이터를 유지.
import { useQuery, QueryClient, QueryClientProvider } from 'react-query';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      useErrorBoundary: true,
      retry: 1,
    },
  },
});

function Dashboard() {
  const { data: userInfo } = useQuery('userInfo', fetchUserInfo);
  const { data: orders } = useQuery('orders', fetchOrders);
  const { data: notifications } = useQuery('notifications', fetchNotifications);

  return (
    <div>
      <h1>Dashboard</h1>
      <div>{userInfo?.name}</div>
      <div>{orders?.length} Orders</div>
      <div>{notifications?.length} Notifications</div>
    </div>
  );
}

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Dashboard />
    </QueryClientProvider>
  );
}
  • 실행 흐름
  1. 컴포넌트가 렌더링될 때 fetchUserInfo, fetchOrders, fetchNotifications가 동시에 실행됩니다.
  2. React Query는 동일한 렌더링 주기에 발생한 세 개의 요청을 배치 처리하여 네트워크 요청 효율성을 높입니다.
  3. 세 개의 쿼리가 완료되면 데이터가 컴포넌트에 전달되고 UI가 리렌더링됩니다.

0개의 댓글