React Router v6结合Formik提交表单后如何重新验证Loader?
核心问题分析
你遇到的问题涉及两个关键层面:一是React Router是否触发Loader重新执行,二是RTK Query的缓存是否会返回旧数据。即使Loader重新执行,若RTK Query缓存未失效,仍会显示旧数据;反之,若Loader未触发,自然无法获取新数据。
解决方案步骤
1. 移除Action中的Redirect,让React Router自动触发Loader
React Router默认在Action执行完成且未返回redirect时,会自动重新运行当前路由的Loader。你当前返回redirect到同一页面,虽理论上也会触发,但直接返回null更简洁,可避免潜在的路由缓存问题。
修改路由Action:
{ path: 'edit', element: <HedrEdit />, loader: args => baseLoader( args, enhancedHedrApi.endpoints.getHedrById, 'hedrId' ), action: async ({ request, params, dispatch }) => { // 新增dispatch参数 const formData = await request.formData(); const values = Object.fromEntries(formData); const data: PutHedrByIdApiArg = { id: Number(params.hedrId), hedr: values, }; await editFetch( enhancedHedrApi.endpoints.putHedrById, data ); // 失效Hedr相关缓存标签(需匹配你的RTK Query标签配置) dispatch(enhancedHedrApi.util.invalidateTags(['Hedr'])); // 返回null,触发React Router自动重新验证Loader return null; }, }
2. 失效RTK Query缓存确保获取最新数据
RTK Query默认会缓存请求结果,因此即使Loader重新执行,也可能返回旧数据。在PUT请求成功后,调用invalidateTags强制失效对应缓存,这样后续的GET请求会拉取最新数据。
注意:
['Hedr']是示例标签,需替换为你在RTK Query定义getHedrById时设置的providesTags值,比如:// 示例RTK Query endpoint定义 getHedrById: builder.query({ query: (id) => `/hedr/${id}`, providesTags: (result) => [{ type: 'Hedr', id: result.id }] })此时失效标签应改为
[{ type: 'Hedr', id: Number(params.hedrId) }],更精准地失效单条数据缓存。
3. 确保Loader中的RTK Query请求能重新获取数据
检查你的baseLoader实现,确保它正确发起RTK Query请求且未设置阻止重新请求的缓存策略。例如:
async function baseLoader(args, endpoint, paramKey) { const param = args.params[paramKey]; const result = await args.dispatch(endpoint.initiate(param)); if (result.isError) { throw result.error; } return result.data; }
由于我们已经失效了缓存,initiate会自动发起新请求,无需额外添加forceRefetch: true。
4. 备选:手动用useRevalidator触发重新验证
如果上述方法仍不生效,可在组件中结合useRevalidator和useNavigation,监听表单提交状态,手动触发Loader重新执行:
import { useRevalidator, useNavigation } from 'react-router-dom'; import { useEffect } from 'react'; const HedrEdit = () => { const { revalidate } = useRevalidator(); const navigation = useNavigation(); const submit = useSubmit(); // 当提交状态从submitting变为idle时,触发重新验证 useEffect(() => { if (navigation.state === 'idle') { revalidate(); } }, [navigation.state, revalidate]); const formikState = useFormik<HedrModel>({ initialValues: { name: data?.name || '', }, validateOnChange: false, validateOnBlur: false, enableReinitialize: true, onSubmit: (values) => { const submitData = { ...values }; submit(submitData, { method: 'put' }); }, }); // ... 表单代码 };
内容的提问来源于stack exchange,提问作者Patrik Vlk

