React Router 6 Action中React Hook Form isSubmitting不更新及RTK异常
React Router 6 数据路由 + RHF + RTK Query 状态不更新问题解决
问题1:React Hook Form 的 formState.isSubmitting 不更新
原因
你用 React Router 的 useSubmit 替代了 RHF 原生提交逻辑,RHF 无法感知 useSubmit 触发的异步 Action 流程,因此不会自动更新 isSubmitting 状态。
解决办法
用 React Router 的 useNavigation 钩子同步加载状态,替代 RHF 自带的 isSubmitting:
import { useNavigation } from 'react-router-dom'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import yourSchema from './your-schema'; function YourForm() { const navigation = useNavigation(); const { register, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(yourSchema), }); // 用导航状态判断是否正在提交 const isSubmitting = navigation.state === 'loading'; const onSubmit = (data) => { useSubmit(data, { method: 'post' }); }; return ( <form onSubmit={handleSubmit(onSubmit)}> {/* 表单字段 */} <button type="submit" disabled={isSubmitting}> {isSubmitting ? '提交中...' : '提交'} </button> </form> ); }
问题2:RTK Query useCreateItemMutation 的 isLoading/error 无变化
原因
你在 Action 里用 store.dispatch 手动触发 mutation,而 useCreateItemMutation 返回的状态仅追踪该钩子自身的 mutate 函数发起的请求,手动 dispatch 的 mutation 不会更新钩子状态。
解决办法
分两种场景处理:
场景1:无需依赖 React Router Action,直接在组件处理提交
直接用 RTK Query 钩子返回的 mutate 函数,RHF 会自动管理 isSubmitting,同时钩子的 isLoading/error 也会正常更新:
import { useNavigate } from 'react-router-dom'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { useCreateItemMutation } from './api-slice'; import yourSchema from './your-schema'; function YourForm() { const navigate = useNavigate(); const [createItem, { isLoading, error }] = useCreateItemMutation(); const { register, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(yourSchema), }); const onSubmit = async (data) => { try { await createItem(data).unwrap(); navigate('/items'); } catch (err) { // 处理错误,比如存入 RHF 的 setError } }; return ( <form onSubmit={handleSubmit(onSubmit)}> {/* 表单字段 */} {error && <div className="error">{error.message}</div>} <button type="submit" disabled={isLoading}> {isLoading ? '提交中...' : '提交'} </button> </form> ); }
场景2:必须用 React Router Action 处理提交
组件里改用 React Router 的 useActionData 获取错误,用 useNavigation 判断加载状态,Action 里保持原有 dispatch 逻辑:
// Action 函数示例 import { redirect } from 'react-router-dom'; import { store } from './store'; import { createItemMutation } from './api-slice'; export async function createItemAction({ request }) { const formData = await request.formData(); const data = Object.fromEntries(formData); try { await store.dispatch(createItemMutation(data)).unwrap(); return redirect('/items'); } catch (err) { // 返回错误信息给组件 return { error: err.message }; } }
// 组件示例 import { useNavigation, useActionData, useSubmit } from 'react-router-dom'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import yourSchema from './your-schema'; function YourForm() { const navigation = useNavigation(); const actionData = useActionData(); const submit = useSubmit(); const { register, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(yourSchema), }); const isSubmitting = navigation.state === 'loading'; const submitError = actionData?.error; const onSubmit = (data) => { submit(data, { method: 'post' }); }; return ( <form onSubmit={handleSubmit(onSubmit)}> {/* 表单字段 */} {submitError && <div className="error">{submitError}</div>} <button type="submit" disabled={isSubmitting}> {isSubmitting ? '提交中...' : '提交'} </button> </form> ); }
注意事项
- 避免混合两种提交模式:要么用 RHF + RTK Query mutate + 手动跳转,要么用 React Router useSubmit + Action + 导航状态,混合会导致状态不同步。
- 确保 Action 已正确配置到对应路由的
action属性中。
内容的提问来源于stack exchange,提问作者Nikolai
相关产品推荐
相关产品推荐

