使用React Query时,点击按钮后useState状态未更新问题排查
问题根源
你代码里的核心问题是错误使用了React Query的mutate方法。mutate是基于回调的异步操作,它不会返回Promise,所以await mutation.mutate(...)根本不会等待API请求完成——save函数会立刻执行完毕,导致setIsSaving(false)或setIsSubmitting(false)几乎和设为true的操作同步执行,状态还没来得及更新就被重置,自然看不到加载状态变化。
修复方案
有两种可行的修复方式,推荐第二种(利用React Query内置状态):
方案一:改用mutateAsync实现等待
React Query提供了mutateAsync方法,它会返回Promise,支持await等待请求完成。修改你的save函数:
const save = async () => { // 把mutate替换为mutateAsync await mutation.mutateAsync({ ...caseData, ...getValues() }); setCaseFormValues(getValues()); };
修改后await save()会真正等待API请求结束,状态会保持为true直到请求完成。
方案二:使用React Query内置的mutation状态(推荐)
React Query的mutation对象本身自带isLoading(新版本可能叫isPending)状态,用来标识当前mutation是否在执行中。你完全不需要自己维护isSaving和isSubmitting,既简化代码又避免状态不同步:
- 父组件传递mutation时,把内置状态也传进去:
// 父组件中 const { mutate, isLoading } = api.postCaseData(caseId); // 传递给CaseForm <CaseForm caseData={caseData} refetch={refetch} isRefetching={isRefetching} mutate={mutate} isMutating={isLoading} />
- CaseForm组件中移除自定义状态,结合操作类型判断加载状态:
const CaseForm = ({ caseData, refetch, isRefetching, mutate, isMutating }) => { const { caseFormValues, setCaseFormValues, setActiveStep } = useCaseProvider(); const initialValues = caseFormValues ?? createInitialValues(caseData); // 移除自定义的useState // const [isSaving, setIsSaving] = useState(false); // const [isSubmitting, setIsSubmitting] = useState(false); // 新增一个状态标识当前操作类型 const [currentAction, setCurrentAction] = useState(null); const save = async (onSuccess) => { await mutate.mutateAsync({ ...caseData, ...getValues() }, { onSuccess: () => { setCaseFormValues(getValues()); onSuccess?.(); setCurrentAction(null); }, onError: () => { setCurrentAction(null); } }); }; const onSave = () => { setCurrentAction('save'); save(); }; const onSubmit = () => { setCurrentAction('submit'); save(() => { setActiveStep(STEPS[Stepper.INCOME]); }); }; // 渲染按钮时这样判断加载状态 // <Button loading={isMutating && currentAction === 'save'}>保存</Button> // <Button loading={isMutating && currentAction === 'submit'}>提交</Button> };
这种方式完全遵循React Query的设计思路,不用手动管理异步状态,减少出错概率。
额外提醒
- 如果你使用的是React Query v4+,
isLoading已被重命名为isPending,请对应调整。 - 如果不需要区分两种操作的加载状态,甚至连
currentAction都可以省略,直接用isMutating控制所有按钮的加载状态。
内容的提问来源于stack exchange,提问作者Leff
相关产品推荐
相关产品推荐

