调用API刷新MaterialUI Autocomplete选项后Formik表单被重置为初始值
修复方案
根因定位
- Formik 组件的
initialValues引用不稳定:如果initialValues直接定义在组件内部没有做引用缓存,父组件重渲染时会生成新的对象引用,Formik 默认检测到initialValues变化就会将整个表单重置为初始值。你调用异步接口时如果触发了clubsLoading等状态更新,会导致父组件重渲染,进而触发该逻辑。 - FastField 使用了内联的 children 函数:每次重渲染时都会生成新的函数实例,导致 FastField 内部的 Autocomplete 组件卸载后重新挂载,字段值会被重置为初始状态。
getClubs或fetchClubs引用不稳定:如果getClubs没有用useCallback包裹,每次渲染会生成新的实例,连带触发关联组件重渲染。
具体修复步骤
- 缓存 Formik 的初始值,保证引用稳定
使用useMemo包裹initialValues,仅当服务端返回的初始编辑数据变化时才更新引用:
const initialValues = React.useMemo(() => ({ club: serverInitData.club, // 补充其他所有表单字段的初始值 }), [serverInitData])
如果不需要在编辑过程中动态更新初始值,可以直接给 Formik 组件添加 enableReinitialize={false} 属性,强制关闭自动重置表单的逻辑:
<Formik initialValues={initialValues} enableReinitialize={false} // 其他 Formik 配置项 > {/* 表单内容 */} </Formik>
- 提取 FastField 的渲染函数并缓存
把 FastField 内部的内联渲染函数提取出来,用useCallback包裹保证引用稳定:
const renderClubAutocomplete = React.useCallback(() => ( <FormField.AutoComplete label="Клуб" name="club" value={values.club} setFieldValue={setFieldValue} setTouched={setFieldTouched} touched={touched.club} errors={errors.club} options={clubs} disabled={clubsLoading} selectionDisabled={clubsLoading} /> ), [values.club, setFieldValue, setFieldTouched, touched.club, errors.club, clubs, clubsLoading])
修改 FastField 调用方式:
<FastField name="club" options={clubs} optionsLoading={clubsLoading} shouldUpdate={(next, prev) => shouldFastFieldRerender(next, prev, getIn) } > {renderClubAutocomplete} </FastField>
- 稳定接口函数引用
确保getClubs函数已经用useCallback包裹,避免每次渲染生成新的实例,导致fetchClubs引用变化触发重渲染。
内容的提问来源于stack exchange,提问作者r.kashigin
相关产品推荐
相关产品推荐

