React

React : TanStack Query LifeCycle, Options

고래고래00 2024. 6. 14. 13:54

TanStack Query LifeCycle

1. active 상태

최초에 데이터 fetching (가져오는 중..)

=> 가지고 온 직후에는 fresh한 상태 (신선한 상태)

=> 일정시간 동안 fresh 유지 (staleTime)

staleTime은 0이 기본값

staleTime을 10초로 설정하면 데이터의 fresh 상태가 10초동안 유지되고 stale 상태로 바뀜

=> stale 상태 (썩은 상태)

=> stale되면 데이터 refetch

refetch trigger

  • refetchOnMount
  • refetchOnWindowFocus
  • refetchOnReconnect ..

 

2. inactive 상태 (현재 페이지에서 사용되지 않는 상태)

다시 사용된다면 active상태로 바뀜

 

3. deleted 상태 (cacheTime이 만료된 상태)

cacheTime : 캐시 데이터를 언제까지 보관할 것인지의 시간

(TanStack Query v5부터 gcTime)

 

상태  설명
fresh 데이터를 새로 패칭할 필요가 없는 상태
staleTime이 지나지 않은 상태로, 캐시 데이터를 그대로 사용 가능
stale 데이터를 새로 패칭해야 하는 상태
staleTime이 지난 후로, 새로운 데이터를 가져오기 위해 쿼리 실행
active 현재 컴포넌트에서 사용 중인 쿼리 상태
컴포넌트가 마운트되어 쿼리를 사용하고 있을 때
inactive 더 이상 사용되지 않는 쿼리 상태
컴포넌트가 언마운트되거나 쿼리가 더 이상 필요하지 않을 때
deleted 캐시에서 제거된 쿼리 상태
gcTime 이 지나면 쿼리가 캐시에서 삭제되었을 때
fetching 데이터를 서버에서 가져오고 있는 상태
이 상태에서는 isFetching이 true로 설정

 

default config(기본 설정)

기본 설정 의미

staleTime: 0 useQuery 또는 useInfiniteQuery에 등록된 queryFn 을 통해 fetch 받아온 데이터는
항상 stale data 취급
refetchOnMount: true useQuery 또는 useInfiniteQuery 가 있는 컴포넌트가 마운트 시 stale data 를 refetch 자동 실행
refetchOnWindowFocus: true 실행중인 브라우저 화면을 focus 할 때 마다 stale data를 refetch 자동 실행
refetchOnReconnect: true Network 가 끊겼다가 재연결 되었을 때 stale data를 refetch 자동 실행
gcTime(cacheTime): 5분
(1000 * 60 * 5 ms)
useQuery 또는 useInfiniteQuery가 있는 컴포넌트가 언마운트 되었을 때 inactive query라 부르며, inactive 상태가 5분 경과 후 GC(가비지콜렉터)에 의해 cache data 삭제 처리
retry: 3 useQuery 또는 useInfiniteQuery에 등록된 queryFn 이 API 서버에 요청을 보내서 실패하더라도 바로 에러를 띄우지 않고 총 3번까지 재요청을 자동으로 시도

 

테스트

테스트를 위해 ReactQueryDevtools 설치

터미널
yarn add @tanstack/react-query-devtools

 

main.jsx에 devtools 삽입

//main.jsx
const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <ReactQueryDevtools initialIsOpen={false} />
      <App />
    </QueryClientProvider>
  </React.StrictMode>
)

 

staleTime을 5초로 설정

더보기

queryClient

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5000
    }
  }
});

처음에는 fresh였다가 5초후에 stale로 변경되는 것을 확인

5초동안 서버에 새로운 데이터를 요청하지 않음

( ∵ 서버에 revalidate 요청은 stale 상태일 때 요청)

더보기

queryClinet말고 useQuery시에도 설정가능

const { data: todos, isPending, isError } = useQuery({
    queryKey: ["todos"],
    queryFn: fetchTodos,
    staleTime: 5000,
  });

동일하게 작동

 

refetchOnMount

마운트 될 때마다 refetch

더보기

queryClient

const queryClient = new QueryClient(
  {
    defaultOptions: {
      queries: {
        staleTime: 1000, // refetch 확인용
        refetchOnMount: true //기본값
      }
    }
  }
);

todos가 사용되지 않는 empty 페이지에서는 inactive상태가 되었다가 다시 사용되는 페이지로 이동하면 fresh로 바뀜

=> todos를 사용하는 컴포넌트가 마운트 되면 refetch가 일어남

 

refetchOnMount : false로 변경하면

사용하는 컴포넌트가 마운트되어도 계속 stale => refetch가 일어나지 않음

 

refetchOnWindowFocus

포커스를 받으면 refetch

더보기
const queryClient = new QueryClient(
  {
    defaultOptions: {
      queries: {
        staleTime: 1000, // refetch 확인용
        refetchOnWindowFocus: true, // 기본값
      }
    }
  }
);

포커스를 다른 탭에 맞췄다가 다시 돌아오면 fresh 상태 => 포커스를 받으면 refetch

refetchOnWindowFouch : false로 변경하면

포커스를 잃었다가 다시 받아도 fresh상태가 아닌 계속 stale 상태로 유지 => refetch가 일어나지 않음

 

refetchOnReconnect도 동일, 기본값 true

true => 인터넷이 끊겼다가 다시 연결되면 refetch

flase => 인터넷이 끊겼다가 다시 연결되어도 refetch X

 

gcTime (inactive 상태의 데이터를 언제까지 저장하고 있을 지)

더보기

queryClient

const queryClient = new QueryClient(
  {
    defaultOptions: {
      queries: {
        staleTime: 1000,
        gcTime: 2000,
      }
    }
  }
);

inacive상태의 todos가 2초있다가 삭제되는 것을 확인

 

retry (요청 실패시 재요청 시도 횟수, 기본값 3)

일부러 로컬호스트 주소를 DB와 다른 곳으로 설정하고 요청

3번 재시도를 한 끝에 오류메시지를 보여줌

다른 설정들과 동일하게 설정 가능

 

헷갈리는 개념 정리

staleTime과 gcTime

  • staleTime : 얼마의 시간이 흐른 뒤에 stale 취급할 건지 (default: 0)
  • gcTime : inactive 된 이후로 메모리에 얼마만큼 있을건지 (default: 5분, gcTime 0되면 삭제처리)

staleTime stale / fresh 의 관계

  • staleTime > 0 이면, fresh data
  • staleTime = 0 이면, stale data

isPending과 isFetching

  • isPending : 새로운 캐시 데이터를 서버에서 받고 있는 지 여부
  • isFetching: 서버에서 데이터를 받고 있는 지 여부
  • => 캐시 데이터가 있는 경우 서버로부터 데이터는 받고있으니 isFetching : true
    하지만 새로운 캐시 데이터를 받고있는 것은 아니니 isPending : false

useQuery할 때, 반드시 알아야 하는 옵션

enabled : 쿼리(queryFn) 실행 여부를 제어, 기본값 true

값을 false로 설정하면 쿼리가 자동으로 실행되지 않음

이 옵션을 사용하여 특정 이벤트 발생 시 쿼리를 실행

 

예시 코드

더보기

예시1)

const { data, refetch } = useQuery({
	queryKey: ["todos"],
	queryFn: getTodos,
	enabled: false
});

return (
	<div>
    <button onClick={() => refetch()}>데이터 불러오기</button>
  </div>
);

// 데이터 불러오기 버튼을 클릭하면 getTodos로 데이터를 가져옴

 

예시2)

// Dependent Query 예제 (순차적 query 실행)
// Get the user
const { data: user } = useQuery({
  queryKey: ['user', email],
  queryFn: getUserByEmail,
})

const userId = user?.id

// Then get the user's projects
const {
  status,
  fetchStatus,
  data: projects,
} = useQuery({
  queryKey: ['projects', userId],
  queryFn: getProjectsByUser,
  // 쿼리는 userId가 존재하는 경우에만 실행
  enabled: !!userId
})

 

select : 쿼리 함수에서 반환된 데이터를 변형

데이터의 특정 부분만 선택하거나 데이터를 변환해서 사용할 때 유용

( 단, 캐시 데이터는 원본 데이터 유지 )

 

예시 코드

더보기

예시)

import { useQuery } from 'react-query'

function User() {
  const { data } = useQuery({
	  queryKey: ["user"],
	  queryFn: fetchUser,
	  select: user => user.username
  });
  
  return <div>Username: {data}</div>
}

// 가져온 user데이터들의 username값들만 뽑아옴