React Query中InvalidateQuery无法自动更新状态与UI问题
问题分析与解决方案
核心问题
- useUpdateRequest钩子参数传递错误:useMutation的配置需传入单个对象,你当前拆分传递
{onSuccess}, {onError}, {onMutate}会导致后续配置覆盖前置项,实际仅最后一个配置生效。 - updateExpenseMutation的onMutate逻辑错误:当前逻辑是往缓存中新增支出,而非更新已有支出,导致缓存数据与实际业务状态不符。
- deleteBudget函数异步操作未同步:同时触发多个updateExpenseMutation但未等待异步操作完成,缓存更新时机混乱,无法触发UI自动刷新。
具体修复步骤
1. 修复useUpdateRequest钩子
将多段配置合并为单个对象传递给useMutation:
import { useMutation } from "react-query"; import axios from "axios"; function useUpdateRequest(url, options) { const updateExpenseMutation = useMutation( async ({ id, data }) => { const response = await axios.put(`${url}/${id}`, data); return response; }, options // 合并为单个配置对象 ); return updateExpenseMutation; } export default useUpdateRequest;
2. 修正updateExpenseMutation的onMutate逻辑
改为定位并更新缓存中对应支出条目,而非新增:
const updateExpenseMutation = useUpdateRequest( "api/expenses", { onSettled: () => { queryClient.invalidateQueries(["expenses"]); }, onMutate: async (updatedExpense) => { const previousExpenses = queryClient.getQueryData(["expenses"]); await queryClient.cancelQueries({ queryKey: ["expenses"] }); // 更新缓存中匹配的支出条目 queryClient.setQueryData(["expenses"], { ...previousExpenses, expenses: previousExpenses.expenses.map(expense => expense._id === updatedExpense.id ? {...expense, budgetId: updatedExpense.data.budgetId} : expense ) }); return { previousExpenses }; }, onError: (err, _, context) => { // 出错时回滚到缓存快照 queryClient.setQueryData(["expenses"], context.previousExpenses); }, } );
3. 优化deleteBudget函数,同步异步操作
使用mutateAsync和Promise.all确保所有异步操作完成后再触发缓存更新:
async function deleteBudget(id) { const { expenses: previousExpenses } = queryClient.getQueryData(["expenses"]) || { expenses: [] }; // 等待预算删除操作完成 await deleteBudgetMutation.mutateAsync(id); // 收集所有支出更新的Promise const updatePromises = previousExpenses .filter(expense => expense.budgetId === id) .map(expense => updateExpenseMutation.mutateAsync({ id: expense._id, data: { ...expense, budgetId: UNCATEGORIZED_BUDGET, }, }) ); // 等待所有支出更新完成 await Promise.all(updatePromises); // 强制触发缓存失效,确保UI同步 queryClient.invalidateQueries(["expenses"]); }
额外说明
- 使用
mutateAsync替代mutate可获取异步操作的Promise,便于控制执行顺序。 - 乐观更新逻辑能让UI即时反馈操作结果,出错时通过
onError回滚缓存,保证数据一致性。
内容的提问来源于stack exchange,提问作者David Francisco
相关产品推荐
相关产品推荐

