본문 바로가기

React/실험실

[React] React-Query - QueryClient stale & cacheTime

앞서 겉핥기에서 React Query의 캐싱은 stale과 cacheTime을 통해 이루어 진다고 말했다. 

 

Stale

말 그대로 " 신선하지 않은 " 을 뜻한다. 

React Query에서는 캐싱된 데이터를 기본적으로 stale 상태로 여긴다. 

 

여기서 말하는 신선하다는 것은 서버에서 조회한 데이터는 요청한 당시의 snapshot이고, 외부 요청으로 

데이터가 변경된 경우 브라우저가 가진 데이터는 오래된 데이터가 되어버려서 stale하다고 하는 것이다. 

 

그러므로 stale 상태란 뜻은 최신화가 필요하다는 것으로 refetch 상황에 refetch가 발생한다. 

 

refetch가 되는 조건으론 

▶ 새로운 Query Instance가 마운트 될 때 ( 페이지를 이동했다가 왔을 경우 ) 

브라우저 화면을 이탈했다가 다시 Focus 할 때 

네트워크가 다시 연결될 때 

설정한 refetch interval에 의한 경우 

 

refetch가 되는 조건에 만족했지만 refetchOnWindowFocus 등의 옵션으로 refetch를 막을 수 있고,

staleTime 옵션으로 설정한 시간 동안 데이터가 stale 되지 않도록 refetch를 막을 수 있다.

 

React Query 캐싱 

React Query에서는 옵션을 설정하지 않으면 캐싱이 발생하지 않는다. 

그래서 캐싱을 제대로 사용하려면 staleTime과 cacheTime을 알아야 한다. 

 

staleTime 

데이터가 fresh 상태에서 stale 상태로 변경되는데 걸리는 시간을 나타내며, default 값은 0이다. 

fresh 상태일때는 페이지를 이동했다가 돌아왔을 경우에도 fetch가 일어나지 않는다. 

 

즉, 데이터가 한번 fetch 되고 staleTIme이 지나지 않았다면 unmount 후 mount가 발생해도 다시 

fetch가 발생하지 않는다. 

 

default 값이 0이기 때문에 받아오는 즉지 stale하다고 판단해서 캐싱 데이터와는 무관하게 

계속 fetching을 수행한다. 

 

그러므로 staleTime을 지정하지 않고 사용한다면 React Query의 캐싱 기능을 활용할 수 없다. 

자주 변경되는 데이터라면 지정하지 않는 편이 좋지만, 정적인 데이터 또는 자주 변경될 필요가 없는 

데이터라면 staleTime을 지정해서 서버의 부담을 줄여주는 것이 좋다. 

 

설정하는 방법으로는

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // 20 second
      staleTime: 1000 * 20,
    },
  },
});

QueryClient에서 전역으로 StaleTime을 설정해줄 수 있다. 

 

  const user = useQuery("users", login, {
    staleTime: 1000 * 20,
  });

또는 useQuery를 에서 바로 옵션을 설정해서 특정 쿼리에만 staleTime을 줄 수 있다. 

 

추가적으로 useQuery는 최초 마운트 시 해당 useQuery가 useEffect처럼 첫 마운트 시 fetcher 함수를 

호출하고, 실패했을 때 retry를 실행한다. 

예를들어서 최초에는 useQuery가 필요없고 특정 작업을 한 뒤에 useQuery가 필요한 경우 

retry로 인해서 서버에 불필요한 요청을 보내게 된다. 

 

이것을 useQuery의 enabled 옵션을 통해서 막아줄 수 있다. 

import axios from "axios";
import { useEffect } from "react";
import { useState } from "react";
import { useQuery } from "react-query";
import { Link } from "react-router-dom";

const login = async () => {
  const { data } = await axios.get("/users");

  return data;
};

const Main = () => {
  const [input, setInput] = useState("");

  const user = useQuery("users", login, {
    staleTime: 1000 * 20,
    enabled: input !== "",
  });

  useEffect(() => {
    setTimeout(() => {
      setInput("123");
    }, 1000);
  }, []);

  console.log(user);

  return (
    <div>
      <Link to={"/mypage"}>마이페이지 이동</Link>
    </div>
  );
};

export default Main;

enabled 옵션은 false인 경우 retry를 발생시키지 않는데, 그럴 경우 status가 idle이 되면서 

retry를 하지 않는다. 

 

그리고 다시 fetching이 필요한 경우 조건을 통해서 위와같이 enabled 옵션을 true로 바꿔주면 다시 데이터를 받아온다. 

 

cacheTime 

데이터가 inactive 상태일 때 캐싱된 상태로 남아있는 시간을 말한다. 

 

쿼리 인스턴스가 unmount되면 데이터는 inactive 상태로 변경되며, 캐시는 cacheTime 만큼 유지된다. 

이걸 cacheTime 만큼 유지시키는 이유는 쿼리 인스턴스가 다시 마운트되면 데이터를 fatch하는 동안 

cacheTime이 지나지 않은 캐시 데이터를 보여준다. 

 

cacheTime이 지나면 가비지 콜렉터로 삭제가 된다. 

 

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // 20 second
      staleTime: 1000 * 20,

      // 40 second
      cacheTime: 1000 * 40,
    },
  },
});

staleTime과 비슷하게 cacheTIme을 사용해서 옵션을 지정할 수 있다. 

useQuery에서도 마찬가지로 개별 Query에 cacheTime을 설정할 수 있다. 

 

유의할 점은 staleTime이 cacheTime보다 길더라도 cacheTime이 지나면 데이터가 사라지기 때문에 

적용할 때 staleTime보다 cacheTime이 더 길어야 한다. 

 

default 값은 staleTime은 0, cacheTime은 5분이다. 

 

그외 옵션 

queries에 staleTime과 cacheTime 외에도 

refetchOnWindowFocus

데이터가 stale 상태일 경우 윈도우 포커싱이 될 때 refetch 실행 옵션을 정할 수 있다. 

▶ default : true

 

refetchOnMount 

데이터가 stale 상태일 경우 마운트 마다 refetch 실행 옵션을 정할 수 있다. 

▶ default : true

 

refetchOnReconnect

데이터가 stale 상태일 경우 재 연결될 때마다 refetch 실행 옵션을 정할 수 있다. 

▶ default : true

 

retry 

실패한 쿼리를 재시도하는 횟수를 정하는 옵션이다. 

만약 true로 설정 시 무한 재시도를 하고, false일 경우 재시도를 하지 않는다. 

▶ default : 3 

 

외에도 있지만 여기까지 적겠다. 

반응형