사이드프로젝트하다가 api에 문제가 생겨서 손보던 중 react-query v5가 나온걸 보고 v5로 업데이트 했다.
인터페이스가 좀 바뀌어서 이것저것 고치는데 onSuccess를 넣을 자리가 안보였다.
검색해보니 react-query v5에서는 onSuccess가 사라졌다고 한다!
이 글에 나와있는데 주요한것만 작성해본다.
나쁜 Callback 제거
useQuery에서 onSuccess, onError, onSetteled가 제거되었다. (useMutation에는 잘 있다고 한다.)
개발자의 의도와 다르게 행동할 수 있기 때문이다.
onError
onError같은 경우는 root의 queryClient에서 사용하라고 한다.
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error) =>
toast.error(`Something went wrong: ${error.message}`),
}),
})
만약 api마다 error message를 커스텀하고 싶을 수 있다. 그땐 이렇게
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error, query) => {
if (query.meta.errorMessage) {
toast.error(query.meta.errorMessage)
}
},
}),
})
export function useTodos() {
return useQuery({
queryKey: ['todos', 'list'],
queryFn: fetchTodos,
meta: {
errorMessage: 'Failed to fetch todos',
},
})
}
onSuccess
아래와 같이 하지 말라고 한다.
export function useTodos() {
const [todoCount, setTodoCount] = React.useState(0)
const { data: todos } = useQuery({
queryKey: ['todos', 'list'],
queryFn: fetchTodos,
//😭 제발 이러지 마세요
onSuccess: (data) => {
setTodoCount(data.length)
},
})
return { todos, todoCount }
}
1. 추가 렌더링 생김
2. 캐시를 사용할 경우 콜백이 실행되지 않을 가능성이 있다.
2번은 한번도 생각해보지 못한 경우인데, staleTime만 정의해놓고 캐시에서 데이터를 읽어올때 onSuccess 는 문제를 일으킬 수 있다.
fetch가 발생해야 onSuccess가 실행되는데 캐시된 데이터를 사용하면 re-fetch되지 않으면서 onSuccess가 호출되지 않는다.
이러한 버그는 이유를 알지 못하면 추적하기 어렵다.
그럼 어떻게 해야할까?
대안 1. 꼭 필요할때 useEffect 쓰기.
이렇게 하면 cache를 사용하더라도 예상대로 동작한다(cache를 사용해도 console.log은 찍힌다 => useEffect의 dependency가 동작한다.)
export function useTodos(filters) {
const { dispatch } = useDispatch()
const query = useQuery({
queryKey: ['todos', 'list', { filters }],
queryFn: () => fetchTodos(filters),
staleTime: 2 * 60 * 1000,
})
React.useEffect(() => {
if (query.data) {
dispatch(setTodos(query.data))
}
}, [query.data])
return query
}
대안2. select 사용하기
select는 data가 존재할때만 호출된다. 그렇기때문에 data가 undefined인 경우를 고려할 필요가 없다.
export const useTodosQuery = () =>
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
select: (data) => data.map((todo) => todo.name.toUpperCase()),
})
연산이 비쌀경우 다음과 같이 메모이제이션도 가능하다.
export const useTodosQuery = () =>
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
// ✅ memoizes with useCallback
select: React.useCallback(
(data: Todos) => data.map((todo) => todo.name.toUpperCase()),
[]
),
})
그 외
여러가지가 있겠지만 cacheTime의 이름이 부적절하다고 판단되어 gcTime으로 바뀌었다.
garbage collect Time인데 훨씬 직관적이다.
'개발 > react-query' 카테고리의 다른 글
tanstack query로 SSR 시키기 (0) | 2024.08.15 |
---|---|
tanstack-query v5 업데이트 기능: useQuery에 onSuccess 삭제 (0) | 2024.06.11 |
refetch와 mutation의 캐시 동작 (0) | 2023.09.12 |
react-query warning : query data cannot be undefined. please make sure to return a value other than undefined from your query function. (0) | 2022.11.19 |
useMutation : mutate는 void, mutateAsync는 promise (0) | 2022.10.19 |