invalidateQueries đánh dấu cache là stale và refetch các query đang active — dữ liệu chắc chắn đúng vì lấy lại từ server, nhưng tốn thêm một round-trip. setQueryData ghi thẳng kết quả mutation vào cache — không tốn request nào, nhưng bạn phải tự bảo đảm dữ liệu ghi vào khớp với thứ server thực sự lưu.
const { mutate } = useMutation({
mutationFn: updateTodo,
onSuccess: (updated) => {
// response trả về đầy đủ entity → ghi thẳng, khỏi fetch lại
qc.setQueryData(['todo', updated.id], updated)
// danh sách có thể đổi thứ tự / phân trang / đếm → để server quyết
qc.invalidateQueries({ queryKey: ['todos', 'list'] })
},
})Quy tắc chọn:
- Response trả về entity đầy đủ và query đích là chi tiết của chính entity đó → setQueryData.
- Mutation ảnh hưởng tới danh sách, thứ tự, bộ đếm, tổng tiền, hoặc server có logic phụ (trigger, tính toán) → invalidateQueries.
Mẹo dùng chung: invalidateQueries({ queryKey: ['todos'] }) khớp theo tiền tố, nên nó vô hiệu hoá cả ['todos', 'list'] lẫn ['todos', id]. Query không active sẽ không refetch ngay mà chỉ bị đánh dấu stale, lần mount sau mới fetch.