
프로젝트에서 @tanstack/react-query를 v4 쓰고 있다가 이번에 v5로 변경하였다.
제일 큰 변화점은 v5부터는 객체 형식만 지원한다는 점이다.
참고
https://tanstack.com/query/v5/docs/react/reference/QueryClient
https://github.com/ssi02014/react-query-tutorial/blob/main/document/v5.md
https://wonsss.github.io/library/tanstack-query-v5/
https://www.moonkorea.dev/React-TanStack-Query-v5-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0-(%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%BF%BC%EB%A6%AC)
v4에서는 useQuery(key, fn, options), useQuery({queryKey, queryFn, ...options}) 두 형태를 모두 지원했는데 이는 유지보수가 힘들고, 매개 변수 타입을 확인하기 위한 런타임 검사도 필요했기 때문에 오로지 객체 형식만 지원하도록 v5에서 변경되었다.
queryClient.getQueryData, queryClient.getQueryState의 인수가 queryKey만 받도록 v5에서 수정되었다.
queryClient.getQueryData(queryKey)
queryClient.getQueryState(queryKey)
Callbacks 함수의 onSuccess, onError, onSettled가 제거되었다.
remove 메서드가 제거되었다.
쿼리를 제거해야하는 경우 queryClient.removeQueries({ queryKey: key })를 사용한다.
isDatEqual을 사용하지 않고 동일한 기능인 structuralSharing으로 활용
cacheTime이 gcTime으로 변경되었다.
useErrorBoundary 옵션은 throwOnError로 이름이 변경됩니다. 리액트 훅의 접두사인 "use"와 특정 컴포넌트명인 "ErrorBoundary"의 사용보다는 옵션이 제공하는 기능에 맞게 다음 렌더 사이클에 에러를 다시 던지는 throwOnError로 변경됩니다.
error의 기본 타입이 Error입니다. 거의 모든 경우에 Error 타입을 갖기 때문에 v5부터 error 필드는 Error 타입으로 추론됩니다.
커스텀 에러를 활용하거나 Error가 아닌 것을 활용하고 싶다면 아래 예제처럼 타입을 구체화할 수 있습니다.
const { error } = useQuery<Group[], string>({
queryKey: ["groups"],
queryFn: fetchGroups,
});
keepPreviousData 옵션과 isPreviousData는 placeholderData 옵션과 isPlaceholderData로 변경됩니다. v5에서 keepPreviousData는 리액트 쿼리에서 제공하는 함수(identity function)로 변경되는데요, 모듈에 불러와 placeholderData의 값으로 사용합니다.
useQuery({
queryKey,
queryFn,
placeholderData: (previousData, previousQuery) => previousData,
// identity function with the same behaviour as `keepPreviousData`
});
Tanstack Query는 visibilitychange 이벤트를 지원하는 브라우저만 지원하도록 결정됐습니다. 따라서, 이제 visibilitychange 이벤트만 독점적으로 사용됩니다.
커스텀 queryClient 인스턴스를 위해 커스텀 context prop이 제거되었습니다.
refetchpage를 제거하고 maxPages가 추가 되었습니다.
infinite Query 옵션에 명시적인 initialPageparam을 전달해야 합니다.
이전 버전에서는 queryFn의 pageParam이 undefined 값을 가져서 0 또는 초기 값을 정의했었는데 undefined는 직렬화되지 않아 initialPageParam 옵션이 추가됐습니다.
Infinite query를 사용할 때 pageParam의 초기 값으로 사용될 initialPageParam 옵션을 전달해야 합니다. 이전 버전에서는 queryFn의 pageParam이 undefined 값을 가져서 0 또는 초기 값을 정의했었는데 undefined는 직렬화되지 않아 initialPageParam 옵션이 추가됐습니다.
v4에서는 더 이상 페이지 없음을 나타내기 위해 명시적으로 undefined를 반환해야 했습니다. v5부터는 undefined 뿐만 아니라 null까지 포함하도록 확장됐습니다.
서버에서의 retry 기본 값은 3에서 0으로 변경됩니다.
status의 loading은 pending으로 변경됩니다.
isLoading은 isPending으로 변경됩니다.
isPending && isFetching의 기능인 isInitialLoading은 isLoading으로 변경됩니다.
v5부터는 낙관적 업데이트를 수행하는 방법을 제공합니다.
const queryInfo = useTodos()
const addTodoMutation = useMutation({
mutationFn: (newTodo: string) => axios.post('/api/data', { text: newTodo }),
onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
})
if (queryInfo.data) {
return (
<ul>
{queryInfo.data.items.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
{addTodoMutation.isPending && (
<li key={String(addTodoMutation.submittedAt)} style={{ opacity: 0.5 }}>
{addTodoMutation.variables}
</li>
)}
</ul>
)
}
위 예제에서는 데이터를 캐시에 직접 쓰는 대신에 mutation이 실행중일 때 UI가 표시되는 방식만 변경합니다. 해당 방법은 낙관적 업데이트를 표시해야 하는 위치가 한 곳만 있는 경우에 효과적입니다
infinite queries도 normal queries처럼 prefetch 할 수 있습니다. 기본으로 한 개 페이지에 대한 쿼리를 prefetch 하지만 pages 옵션과 getNextPageParam옵션으로 한 개 이상의 페이지를 prefetch 할 수 있습니다.
const prefetchTodos = async () => {
// The results of this query will be cached like a normal query
await queryClient.prefetchInfiniteQuery({
queryKey: ["projects"],
queryFn: fetchProjects,
initialPageParam: 0,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
pages: 3, // prefetch the first 3 pages
});
};
useQueries의 combine으로 응답(쿼리에 대한 정보 등)을 하나의 값으로 사용할 수 있습니다.
다만 위의 경우 쿼리의 data와 pending 값만 반환되고 쿼리에 대한 나머지 정보는 유실됩니다.
data fetching에 대한 suspense가 안정화가 되었습니다.
useQuery에서 사용하던 suspense: boolean 옵션은 제거되고 useSuspenseQuery, useSuspenseInfiniteQuery와 useSuspenseQueries이 추가되었습니다.
suspense와 관련된 자세한 내용은 suspense를 참고해주시길 바랍니다.
Tanstack Query v5는 필요한 TypeScript 최소 버전이 v4.7입니다.
Tanstack Query v5는 필요한 React 최소 버전이 v18.0입니다. 이는 React v18 이상에서만 사용할 수 있는 useSyncExternalStore 훅을 사용하고 있기 때문입니다.
리액트 쿼리는 최신 브라우저에 최적화되어 있습니다.
Chrome >= 91
Firefox >= 90
Edge >= 91
Safari >= 15
iOS >= 15
opera >= 77