React StrictMode为何会触发localStorage重复初始化?
React StrictMode 为啥会影响 localStorage 的初始化?
问题表现
移除 StrictMode 前
index.js
import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <App /> </React.StrictMode> );
执行console.log(localStorage.getItem("comments"))后,控制台输出:
[{"name":"1","comment":"asdjflisadhj"}] []
移除 StrictMode 后
index.js
... root.render(<App />); ...
执行console.log(localStorage.getItem("comments"))后,控制台输出:
[{"name":"1","comment":"asdjflisadhj"}]
原因拆解
React StrictMode 在开发环境下有个特殊行为:会重复执行组件的副作用函数(比如useEffect)、挂载/卸载逻辑,目的是帮你找出那些“只跑一次没问题,重复跑就出bug”的代码。
结合你的组件代码来看:
const Info = () => { const [name, setName] = useState(""); const [comment, setComment] = useState(""); const [comments, setComments] = useState([]); useEffect(() => { const savedComments = localStorage.getItem("comments"); if (savedComments) { setComments(JSON.parse(savedComments)); } console.log(localStorage.getItem("comments")); }, []); useEffect(() => { localStorage.setItem("comments", JSON.stringify(comments)); }, [comments]); ...
StrictMode下的完整执行流程是这样的:
- 第一次挂载:
- 第一个空依赖的
useEffect执行:读出localStorage里的有效评论数组,调用setComments更新状态,同时打印这个有效值。 - 因为
comments从初始的[]变成了有效数组,触发第二个useEffect,把更新后的数组存回localStorage,此时localStorage是正常的。
- 第一个空依赖的
- StrictMode触发第二次重复执行(模拟卸载后重新挂载):
- 第一个
useEffect再次执行:此时读出的localStorage还是有效值,所以打印出来。 - 但组件状态会被重置回初始的
[](相当于重新初始化组件),紧接着第二个useEffect触发,把空数组存入localStorage,直接覆盖了之前的有效值。
- 第一个
- 这就导致你看到控制台先打印正常数组,再打印空数组,最终localStorage被改成了空数组。
移除StrictMode后,副作用只执行一次,不会触发这次重置,所以localStorage能保持正确的值。
可选修复方案
如果想保留StrictMode的检测功能,又不想出现这个问题,可以修改第二个useEffect,避免用初始空数组覆盖已有数据:
useEffect(() => { // 只有当comments不是初始空数组时,才更新localStorage if (comments.length > 0) { localStorage.setItem("comments", JSON.stringify(comments)); } }, [comments]);
或者更严谨点,先对比localStorage里的值和当前comments,不一样再更新,减少不必要的存储操作。
内容的提问来源于stack exchange,提问作者PARKHEECHANG
相关产品推荐
相关产品推荐

