如何在React Query中跨组件订阅mutation状态变化
跨组件订阅React Query Mutation状态的解决方案
问题原因
你当前的代码中,每个组件调用useUpdateResidence时都会创建独立的Mutation实例,不同实例的状态完全隔离,所以其他组件无法感知表单组件触发的Mutation状态变化。
解决方法
方法1:利用React Query的Mutation Key共享实例
给useMutation添加唯一的mutationKey,确保相同caseId下的Mutation复用同一个实例,状态自动同步。
修改useUpdateResidence钩子:
export const useUpdateResidence = (caseId: number) => { const queryClient = useQueryClient(); const [error, setError] = useState(undefined); const mutation = useMutation({ // 新增mutationKey,用caseId区分不同案件的更新操作 mutationKey: ["update-residence", caseId], mutationFn: async (payload: UpdateResidenceRequest): Promise<CaseResponse> => { const { data } = await CASE_API.api.updateCase(caseId, payload); return data; }, onSuccess: (data) => { queryClient.setQueryData(["case", caseId], data); setError(undefined); }, onError: (error) => { console.log("onError", error); setError(error); }, }); return { mutation, error }; };
之后其他组件只需传入相同的caseId调用useUpdateResidence,就能拿到同一个Mutation实例,实时获取状态变化。
方法2:通过React Context共享Mutation实例
创建Context将Mutation实例注入到组件树中,让需要订阅状态的组件从Context中获取同一个实例。
- 创建Context和Provider:
import { createContext, useContext, ReactNode } from 'react'; import { useUpdateResidence } from './path-to-your-hook'; const UpdateResidenceMutationContext = createContext<ReturnType<typeof useUpdateResidence> | null>(null); export const UpdateResidenceMutationProvider = ({ caseId, children }: { caseId: number; children: ReactNode }) => { const mutationData = useUpdateResidence(caseId); return ( <UpdateResidenceMutationContext.Provider value={mutationData}> {children} </UpdateResidenceMutationContext.Provider> ); }; // 自定义钩子简化Context获取 export const useSharedUpdateResidenceMutation = () => { const context = useContext(UpdateResidenceMutationContext); if (!context) { throw new Error('useSharedUpdateResidenceMutation must be used within UpdateResidenceMutationProvider'); } return context; };
- 在表单组件的父层级包裹Provider:
// 假设父组件中能获取到caseId const { caseId } = useCase(); return ( <UpdateResidenceMutationProvider caseId={caseId}> <FormComponent /> <OtherComponentThatNeedsMutationState /> </UpdateResidenceMutationProvider> );
- 在表单和订阅组件中使用共享钩子:
// 表单组件中 export const useOnSaveCase = () => { const { reset } = useFormContext<CaseFormValues>(); const updateCase = useSharedUpdateResidenceMutation(); return (values: CaseFormValues) => { updateCase.mutation.mutate(createPayload(values), { onSuccess: () => reset(values, { keepErrors: true, keepValues: true, keepDefaultValues: true, keepDirtyValues: true, }), }); }; }; // 订阅组件中 const caseMutation = useSharedUpdateResidenceMutation(); console.log("is pending", caseMutation.mutation.isPending); console.log("is success", caseMutation.mutation.isSuccess);
方法3:通过Mutation Cache手动订阅状态
如果只需要监听状态而不需要触发Mutation,可以直接从React Query的Mutation Cache中获取实例并订阅。
import { useQueryClient } from '@tanstack/react-query'; import { useCase } from './path-to-your-hooks'; const MutationStatusWatcher = () => { const { caseId } = useCase(); const queryClient = useQueryClient(); useEffect(() => { // 根据mutationKey查找对应的Mutation实例 const mutation = queryClient.getMutationCache().find(["update-residence", caseId]); if (!mutation) return; // 订阅状态变化 const unsubscribe = mutation.subscribe((state) => { console.log("is pending", state.isPending); console.log("is success", state.isSuccess); }); // 组件卸载时取消订阅 return unsubscribe; }, [caseId, queryClient]); return null; };
内容的提问来源于stack exchange,提问作者Leff
相关产品推荐
相关产品推荐

