Skip to content

Latest commit

 

History

History
105 lines (82 loc) · 4.37 KB

5주차_조명근_개인.md

File metadata and controls

105 lines (82 loc) · 4.37 KB

Tanstack-query의 캐시 무효화 전략

캐시 무효화는 언제 필요할까요?
데이터가 오래되어서 최신 데이터를 받아와야 하는 경우, 업데이트 된 데이터로 최신화가 필요한 경우, 동시성 문제 방지 등등...
사용자가 꼭 수동으로 데이터를 가져와야 하는 경우가 아니라면 적절한 시점에 데이터를 최신화해주는게 좋은 UX로 가는길로 보입니다.

tanstack-query는 DX, UX를 위한 몇가지 전략을 제시합니다. queryKey를 기반으로 각 쿼리 데이터를 식별하는데, queryKey를 사용한 캐시 전략은 key 관리방법에 가깝기 때문에 제외하고 기능적으로 어떤 캐시 관리 방법 있는지 살펴보겠습니다.

1. 자동 refetch / TTL 기반 캐시

자동 리페치는 특정 이벤트 발생 시, 쿼리가 자동으로 다시 실행되도록 하는 전략입니다.

const { data, isLoading } = useQuery("todos", fetchTodos, {
  refetchOnWindowFocus: true, // 브라우저 창 포커스 시 자동 리페치
  refetchOnMount: true, // 컴포넌트 마운트 시 자동 리페치
  refetchInterval: 60000, // 60초마다 자동 리페치
  staleTime: 60000, // 1분 동안 데이터를 "신선한" 상태로 간주
  cacheTime: 300000, // 5분 동안 캐시 유지
});

2. 수동 무효화 (Invalidate Queries)

queryClient.invalidateQueries를 사용해 특정 쿼리 키를 가진 데이터를 수동으로 무효화하고, 다시 가져올 수 있습니다.

import { useMutation, useQueryClient } from "@tanstack/react-query";

const queryClient = useQueryClient();

const mutation = useMutation(updateTodo, {
  onSuccess: () => {
    // 'todos' 키를 가진 모든 쿼리 무효화
    queryClient.invalidateQueries("todos");
  },
});

3. 낙관적 업데이트 (Optimistic Updates)

데이터가 성공적으로 업데이트된 것처럼 UI를 미리 업데이트한 후 서버 응답에 따라 상태를 조정합니다.

const mutation = useMutation(updateTodo, {
  onMutate: async (newTodo) => {
    // 쿼리 무효화 전 작업 취소
    await queryClient.cancelQueries("todos");

    // 기존 데이터 저장
    const previousTodos = queryClient.getQueryData("todos");

    // 미리 UI 업데이트
    queryClient.setQueryData("todos", (old) =>
      old.map((todo) => (todo.id === newTodo.id ? newTodo : todo))
    );

    return { previousTodos };
  },
  onError: (err, newTodo, context) => {
    // 롤백
    queryClient.setQueryData("todos", context.previousTodos);
  },
  onSettled: () => {
    // 작업 완료 후 무효화
    queryClient.invalidateQueries("todos");
  },
});

낙관적 업데이트를 완료한 후에, invalidateQueries를 실행합니다.
왜 refetch를 하지않고 invalidation 동작을 하는걸까요?

invalidateQueries vs refetch

invalidate: 무효화하다.

tanstack에서 invalidation은 쿼리의 데이터가 더이상 최신 데이터가 아님을 의미합니다.
tanstack-query에서 데이터를 새로 fetch하는 조건은 아래와 같습니다.

  1. 캐시상태가 유효한가
    1. stale: 유효하다
    2. staleTime을 사용하거나, 수동으로 invalidate하는 경우
  2. 쿼리가 다시 활성화 될 때
    1. 쿼리가 비활성화 되었다가 다시 활성화 된 경우
    2. refetchOnWindowFocusrefetchOnReconnect의 옵션을 사용하는 경우
  3. queryKey가 변경될 때
    1. useQuery(["todos", { userId }], fetchTodos); 이 경우 userId가 변경되면 이전 캐시 데이터를 무시하고 새로 fetch함.
  4. 수동으로 데이터를 fetch하는 경우
    1. refetch 사용
    2. invalidate후 쿼리가 active 되어있는 상태라면 자동으로 쿼리를 fetch
      1. 쿼리가 Active 되어있다: 쿼리를 사용하는 컴포넌트가 렌더링 되어있는 경우
      2. queryClient.invalidateQueries(["todos"]);
  5. 캐시가 만료된 경우
    1. catchTime 옵션에 따라 쿼리 캐시가 만료된 경우 (기본 5분)
    2. useQuery(["todos"], fetchTodos, { cacheTime: 1000 * 60 * 10 }); // 10분

이런 조건일때 tanstack-query에서는 데이터를 새로 가져옵니다.

따라서 invalidateQuery는 쿼리가 더이상 유효(stale) 하지않음을 알려주고, 쿼리가 사용중(actvie)인 경우(컴포넌트가 렌더링 되어있는 경우) 데이터를 새로 fetch합니다.