Next.js
React Query 캐시 시간을 무작정 늘리기 전에 본 것들
목록 화면이 오래된 데이터를 보여 준 원인을 staleTime, invalidation, queryKey 관점에서 비교했다.
문제 장면
목록에서 게시글을 수정하고 돌아왔는데 제목이 예전 값으로 남아 있었다. 새로고침하면 정상이라서 API보다는 프론트 캐시 문제에 가까웠다. 처음에는 staleTime을 줄이면 끝날 줄 알았지만, 그렇게 하면 요청 수가 늘고 근본 원인은 남는다.
React Query를 쓸 때는 캐시 시간을 하나의 숫자로만 보면 자주 꼬인다. 이 문제는 queryKey, staleTime, invalidateQueries가 같이 얽혀 있었다.
세 가지를 구분했다
staleTime은 데이터가 신선하다고 간주되는 시간이다. 이 시간 안에는 다시 마운트해도 자동 재요청을 덜 한다.
useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
staleTime: 1000 * 60,
});
gcTime은 안 쓰는 캐시를 메모리에 얼마나 둘지에 가깝다. 예전 글이나 예전 예제에서는 cacheTime이라는 이름으로 봤을 수도 있다.
수정 후 목록을 바로 맞추려면 캐시 시간을 건드리기보다 무효화를 명확히 하는 편이 낫다.
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: updatePost,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
내가 실제로 틀린 부분
나는 목록 조회에는 ['posts', page]를 쓰고, 무효화에는 ['post']를 넣고 있었다. 단수와 복수 차이라서 눈에 잘 안 들어왔다. Devtools를 열어 보니 캐시는 그대로 살아 있고 다른 키만 무효화되고 있었다.
// 조회
useQuery({ queryKey: ['posts', page], queryFn: fetchPosts });
// 잘못된 무효화
queryClient.invalidateQueries({ queryKey: ['post'] });
수정 후에는 키를 상수로 빼서 같은 이름을 쓰게 했다.
const postKeys = {
list: (page: number) => ['posts', page] as const,
lists: () => ['posts'] as const,
};
선택 기준 비교
상황별로 이렇게 정리했다.
- 데이터가 자주 안 바뀐다:
staleTime을 길게 둔다 - 수정 직후 화면이 어긋난다: mutation 성공 시 invalidate를 본다
- 특정 상세만 바뀐다: 상세 key와 목록 key를 따로 무효화한다
- 요청이 너무 많다: staleTime보다 컴포넌트 remount 구조도 확인한다
- 값이 계속 안 바뀐다: queryKey가 실제 변수 변화를 포함하는지 본다
결론 대신 메모
캐시는 빠르게 만드는 도구지만, 틀린 데이터를 오래 보여 주면 오히려 신뢰를 깎는다. 나는 이제 캐시 시간을 늘리기 전에 Devtools에서 queryKey 목록을 먼저 확인한다. 숫자 조절보다 이름을 맞추는 일이 먼저였다.