如何避免子组件状态变化时重新初始化Formik单个字段
解决方案
方法1:监听Recoil状态,单独更新Formik字段
保留enableReinitialize用于提交后的表单重置,同时通过监听Recoil状态变化,调用Formik的setFieldValue单独更新目标字段,避免重置整个表单。
修改后的父组件代码:
const MembersCreate = memo(() => { const urlGDPR = useRecoilValue(urlGDPRState); // 初始化时gdpr_form_link设为空,后续通过setFieldValue更新 const initialValues = { forename: '', surname: '', gdpr_form_link: '', // 其他字段 }; // 获取Formik上下文实例 const { setFieldValue } = useFormikContext(); // 监听urlGDPR变化,仅更新指定字段 useEffect(() => { if (urlGDPR) { setFieldValue('gdpr_form_link', urlGDPR); } }, [urlGDPR, setFieldValue]); return ( <Formik enableReinitialize={true} initialValues={initialValues} onSubmit={(values, formik) => { mutate(values, { onSuccess: () => formik.resetForm() }); }} > <Form> <UploadWidget /> <CustomTextField name="gdpr_form_link" readOnly={true}/> </Form> </Formik> ); });
优势:
enableReinitialize依然生效,提交成功后formik.resetForm()可以正确重置所有字段到初始值- 当
urlGDPRState更新时,仅修改gdpr_form_link字段,完全不影响用户已填写的其他内容
补充:修复子组件内存泄漏问题
子组件中需要在卸载时销毁Cloudinary widget实例,避免内存泄漏:
const UploadWidget = () => { const [, setUrlGDPR] = useRecoilState(urlGDPRState); useEffect(() => { const widget = window.cloudinary.createUploadWidget( { cloudName: '*removed*', uploadPreset: '*removed*' }, (error, result) => { if (result?.event === 'success') setUrlGDPR(result.info.secure_url); } ); // 组件卸载时销毁widget return () => widget.destroy(); }, []); // 添加触发上传的按钮(原代码缺失此部分) return <button onClick={() => widget.open()}>上传GDPR表单</button>; };
内容的提问来源于stack exchange,提问作者Jess
相关产品推荐
相关产品推荐

