React项目中Formik因初始值变更引发无限渲染的问题求助
解决Formik结合localStorage导致的无限渲染问题
你遇到的这个无限渲染问题,根源其实出在prefilledValues的获取方式和useEffect的依赖设置上,咱们一步步拆解并解决它:
问题核心分析
你现在的代码里,prefilledValues是在组件每次渲染时直接从localStorage读取并解析的——这意味着每次组件渲染,它都会生成一个全新的对象引用。而你的useEffect依赖数组里包含了prefilledValues,同时useEffect内部又会更新localStorage,这就形成了一个死循环:
- 组件渲染,读取localStorage得到新的
prefilledValues对象 - useEffect检测到
prefilledValues引用变化,执行更新localStorage的操作 - localStorage更新后,组件因formik.values变化重新渲染,再次读取localStorage生成新的
prefilledValues - 循环回到步骤2,最终导致组件无限渲染、页面无响应
最简单的修复方案
我们只需要把初始值的获取逻辑放到useState里,让它只在组件第一次挂载时读取一次localStorage,这样initialValues的引用就不会每次渲染都变化:
// 用useState初始化,仅在组件挂载时读取一次localStorage const [initialValues] = useState(() => { const savedData = window.localStorage.getItem("pre-signup-form"); // 这里填你的表单默认初始值,比如name为空字符串 return savedData ? JSON.parse(savedData) : { name: "" }; }); // 初始化Formik时使用这个固定的initialValues const formik = useFormik({ initialValues: initialValues, // 你的其他Formik配置(比如validationSchema、onSubmit等) }); // 修改useEffect的依赖,只监听formik.values的变化 useEffect(() => { window.localStorage.setItem( "pre-signup-form", JSON.stringify(formik.values) ); }, [formik.values]);
这样调整后:
- initialValues只会在组件第一次加载时从localStorage读取,后续不会再重新生成新对象
- useEffect只在formik的表单值变化时更新localStorage,不会因为引用变化被误触发
- 彻底打破了之前的循环逻辑
进阶:支持外部修改localStorage同步(可选)
如果你希望其他页面或浏览器标签页修改了pre-signup-form的localStorage数据时,当前组件的表单能同步更新,可以添加storage事件监听,但要注意避免自身更新导致的循环:
const [initialValues] = useState(() => { const savedData = window.localStorage.getItem("pre-signup-form"); return savedData ? JSON.parse(savedData) : { name: "" }; }); const formik = useFormik({ initialValues: initialValues, onSubmit: (values) => { // 你的表单提交逻辑 }, }); // 监听外部的storage变化(比如其他标签页修改了localStorage) useEffect(() => { const handleExternalStorageChange = (e) => { if (e.key === "pre-signup-form") { const updatedValues = JSON.parse(e.newValue); // 用Formik的setValues方法更新表单值,避免直接修改state引发的问题 formik.setValues(updatedValues); } }; window.addEventListener("storage", handleExternalStorageChange); // 组件卸载时移除监听 return () => window.removeEventListener("storage", handleExternalStorageChange); }, [formik]); // 同步自身表单修改到localStorage useEffect(() => { window.localStorage.setItem( "pre-signup-form", JSON.stringify(formik.values) ); }, [formik.values]);
这个方案里,我们把自身修改localStorage和外部修改localStorage的逻辑分开,既实现了跨标签页的数据同步,又不会触发无限渲染。
内容的提问来源于stack exchange,提问作者Mahima Sukhija
相关产品推荐
相关产品推荐

