BlitzJS表单执行update mutation时回显初始值问题解决方案
react-final-form 默认在提交异步阶段结束、未更新表单初始值的间隙,会自动读取绑定的initialValues重新渲染表单。你的代码里initialValues绑定的是Blitz查询返回的旧event数据:updateEventMutation执行完成后,Blitz会临时失效对应实体的旧查询缓存,此时setQueryData还没执行,event还是提交前的旧值,表单就会短暂回显初始值;等setQueryData把缓存更新为接口返回的新数据后,initialValues才会变成最新值,表单恢复正确展示,就出现了你看到的闪回问题。
优先选择第一个方案,改动最小,不会影响原有缓存和提交逻辑,适配90%以上的表单场景:
开启表单的
keepDirtyOnReinitialize配置
这是react-final-form原生支持的属性,设为true后,只要表单有过用户输入/处于提交完成后的状态,就算initialValues临时变动,也不会用旧值覆盖当前表单展示的内容,直接消除中间闪回。你只需要给EventForm传入这个属性即可,如果EventForm是自定义封装组件,记得把属性透传给内部的react-final-form实例:<EventForm keepDirtyOnReinitialize={true} onCancel={() => router.push(Routes.ShowEventPage({ eventId: event.id }))} schema={updateEventSchema} initialValues={event} onSubmit={async (values) => { try { const updated = await updateEventMutation(values) await setQueryData(updated) router.push(Routes.ShowEventPage({ eventId: event.id })) } catch (error: any) { console.error(error) return { [FORM_ERROR]: error.toString(), } } }} />关闭mutation的自动缓存失效
Blitz的useMutation默认会在请求结束后自动使关联查询的缓存失效,这是触发旧值回显的直接诱因。你可以给mutation传入配置关闭这个默认行为,等手动更新完缓存再同步状态,就不会出现缓存临时回退的间隙:const [updateEventMutation] = useMutation(updateEvent, { invalidateQueries: false })用这个方案要注意确认其他关联该实体的页面不会因为缓存不自动失效出现数据不一致问题。
提交成功后第一时间重置表单初始值
react-final-form的onSubmit回调第二个参数是表单实例,你拿到mutation返回的最新数据后,立刻调用form.reset把表单初始值设为最新数据,不用等外层查询缓存更新,也能避免旧值渲染:onSubmit={async (values, form) => { try { const updated = await updateEventMutation(values) // 拿到最新数据立刻重置表单初始值 form.reset(updated) await setQueryData(updated) router.push(Routes.ShowEventPage({ eventId: event.id })) } catch (error: any) { console.error(error) return { [FORM_ERROR]: error.toString(), } } }}用这个方案需要确认你封装的
EventForm没有拦截onSubmit参数,能把form实例透传到自定义的提交逻辑里。
注意:不要为了规避这个问题给表单加
destroyOnUnmount={false}或者强行在提交时锁定整个表单渲染,这类方案会引入表单状态残留、提交按钮重复触发等额外问题。
内容的提问来源于stack exchange,提问作者mab

