본문으로 건너뛰기

변형 응답에 의한 갱신

서버에서 객체를 갱신하는 변형을 처리할 때, 변형의 응답으로 새 객체가 자동으로 반환되는 것이 일반적입니다. 해당 항목에 대한 질의를 다시 가져오고 이미 가지고 있는 데이터에 대한 네트워크 호출을 낭비하는 대신, 변형 함수가 반환한 객체를 활용할 수 있습니다. 질의 클라이언트의 setQueryData 메서드를 사용하면 즉시 새 데이터로 기존 질의를 갱신할 수 있습니다.

tsx
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: editTodo,
onSuccess: data => {
queryClient.setQueryData(['todo', { id: 5 }], data)
}
})
mutation.mutate({
id: 5,
name: 'Do the laundry',
})
// 다음 질의는 성공한 변형의 응답으로 갱신됩니다.
const { status, data, error } = useQuery({
queryKey: ['todo', { id: 5 }],
queryFn: fetchTodoById,
})
tsx
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: editTodo,
onSuccess: data => {
queryClient.setQueryData(['todo', { id: 5 }], data)
}
})
mutation.mutate({
id: 5,
name: 'Do the laundry',
})
// 다음 질의는 성공한 변형의 응답으로 갱신됩니다.
const { status, data, error } = useQuery({
queryKey: ['todo', { id: 5 }],
queryFn: fetchTodoById,
})

onSuccess 논리를 재사용 가능한 변형에 연결할 수 있습니다. 이를 위해 다음과 같은 커스텀 훅을 만들 수 있습니다.

tsx
const useMutateTodo = () => {
const queryClient = useQueryClient()
return useMutation({
mutationFn: editTodo,
// 두 번째 인수는 mutate 함수가 받는 변수 객체입니다.
onSuccess: (data, variables) => {
queryClient.setQueryData(['todo', { id: variables.id }], data)
},
})
}
tsx
const useMutateTodo = () => {
const queryClient = useQueryClient()
return useMutation({
mutationFn: editTodo,
// 두 번째 인수는 mutate 함수가 받는 변수 객체입니다.
onSuccess: (data, variables) => {
queryClient.setQueryData(['todo', { id: variables.id }], data)
},
})
}

불변성

setQueryData를 통한 갱신은 불변 방식으로 수행되어야 합니다. (캐시에서 검색한) 데이터를 변형하여 캐시에 직접 쓰지 마세요. 처음에는 작동할 수 있지만 그 과정에서 미묘한 버그가 발생할 수 있습니다.

tsx
queryClient.setQueryData(
['posts', { id }],
(oldData) => {
if (oldData) {
// ❌ 이렇게 하지 마세요.
oldData.title = 'my new post title'
}
return oldData
})
queryClient.setQueryData(
['posts', { id }],
// ✅ 이게 옳은 방식입니다.
(oldData) => oldData ? {
...oldData,
title: 'my new post title'
} : oldData
)
tsx
queryClient.setQueryData(
['posts', { id }],
(oldData) => {
if (oldData) {
// ❌ 이렇게 하지 마세요.
oldData.title = 'my new post title'
}
return oldData
})
queryClient.setQueryData(
['posts', { id }],
// ✅ 이게 옳은 방식입니다.
(oldData) => oldData ? {
...oldData,
title: 'my new post title'
} : oldData
)