如何在React Query多次重取数据时保留历史有效数据?
问题分析
你的核心问题出在两处:
- 轮询未成功时,
useQuery的queryFn返回了undefined,直接把查询的data字段置为undefined,覆盖了之前的成功数据; - 输入文本变化时,查询key中的
text更新触发了新查询,即便开启了keepPreviousData,新查询返回的undefined最终还是会替换旧的成功数据。
下面提供两种直接可行的解决方案:
方案一:单独维护最后成功的数据状态
在Hook内部新增状态存储最后一次成功返回的数据,让组件优先展示这个状态,完全忽略轮询过程中的无效数据。
修改后的完整代码:
export function useSuggestions( text: string, id: string, ): { data: TaskTextStatus | undefined; isLoading: boolean; isFetching: boolean } { const [task, setTask] = useState<string>(); const [stopRefetch, setStopRefetch] = useState(false); // 新增:专门存储最后一次成功的任务数据 const [lastSuccessData, setLastSuccessData] = useState<TaskTextStatus>(); const [textDebounced] = useDebounce(text, 1000); useEffect(() => { mutate(text); }, [textDebounced]); const { mutate } = useMutation( ["suggestions", id, text], async (text: string) => { if (!text) return; const res = await sendToBackground<{ text: string }, TaskTextSubmit>({ name: "send-text", body: { text }, }); return res; }, { onSuccess(data) { if (!data) return; setTask(data.task_uuid); }, onError(e) { console.log(e, "ERROR"); }, }, ); const queryResult = useQuery( // 调整查询key:用task_uuid替代text,只有新任务创建时才启动新查询 ["suggestions", id, task], async () => { if (!task) throw new Error("无任务UUID"); setStopRefetch(false); const res = await sendToBackground<{ task_uuid: string }, TaskTextStatus>({ name: "check-task", body: { task_uuid: task }, }); if (res.is_success) { return res; } else { // 未成功时抛出错误,避免返回undefined覆盖数据 throw new Error("任务未完成"); } }, { enabled: !!task, refetchInterval: stopRefetch ? false : 2000, keepPreviousData: true, refetchIntervalInBackground: true, refetchOnWindowFocus: false, onSuccess(data) { if (data?.is_success) { // 仅在任务成功时更新最后成功数据 setLastSuccessData(data); setStopRefetch(true); setTask(""); } }, onError(err) { // 只有非任务pending的错误才停止轮询 if (err.message !== "任务未完成") { setStopRefetch(true); } }, }, ); // 返回最后成功数据和查询状态,供组件使用 return { data: lastSuccessData, // 只有首次加载且无历史数据时才显示加载状态 isLoading: queryResult.isLoading && !lastSuccessData, isFetching: queryResult.isFetching, }; }
方案二:利用React Query错误机制保留旧数据
React Query在查询抛出错误时,不会更新data字段,会自动保留之前的成功数据。只要让未成功的轮询抛出错误,就能实现需求。
修改核心部分代码:
// ... 其他代码保持不变 const queryResult = useQuery( ["suggestions", id, text], async () => { if (!task) throw new Error("无任务可用"); setStopRefetch(false); const res = await sendToBackground<{ task_uuid: string }, TaskTextStatus>({ name: "check-task", body: { task_uuid: task }, }); // 未成功时抛出错误,阻止data被更新 if (!res.is_success) { throw new Error("任务处理中"); } return res; }, { enabled: !!task, refetchInterval: stopRefetch ? false : 2000, keepPreviousData: true, refetchIntervalInBackground: true, refetchOnWindowFocus: false, onSuccess(data) { if (data?.is_success) { setStopRefetch(true); setTask(""); } }, onError(err) { // 仅在非任务pending的错误时停止轮询 if (err.message !== "任务处理中") { setStopRefetch(true); } }, }, ); return queryResult;
使用时,直接用queryResult.data即可,它会始终保留最后一次成功返回的数据,直到新的成功数据到来。
内容的提问来源于stack exchange,提问作者Devkey
相关产品推荐
相关产品推荐

