React页面刷新后useEffect导致localStorage存储数据丢失问题排查
问题原因与解决方案
核心问题
你遇到的问题根源有两个:
- 初始state的副作用:你在
useState里直接用nanoid()生成初始笔记ID,这意味着每次组件初始化(包括页面刷新)都会生成全新的初始笔记数组。而依赖notes的第二个useEffect会在组件首次渲染时就执行,把这个全新的初始数组写入localStorage,直接覆盖掉之前保存的数据。 - Strict Mode的放大效应:React开发环境默认开启Strict Mode,它会让组件初始化和
useEffect执行两次。第一次挂载时,你的第一个useEffect读取到旧的保存数据并更新notes,但第二次挂载时,组件又会重新生成初始笔记数组,再次触发第二个useEffect覆盖localStorage,最终页面显示的就是硬编码的初始数据。
修复方案
最简洁靠谱的方式是把初始state的默认值直接从localStorage读取,去掉第一个useEffect,避免顺序冲突:
const [notes, setNotes] = useState(() => { // 初始化时优先读取localStorage,没有的话再用默认数据 const savedNotes = localStorage.getItem('react-notes'); if (savedNotes) { return JSON.parse(savedNotes); } // 只有localStorage为空时才生成默认笔记 return [ { noteId: nanoid(), text: 'This is my 1st note!', date: '30/07/2022' }, { noteId: nanoid(), text: 'This is my 2nd note!', date: '30/07/2022' } ]; }); // 只保留这个useEffect,当notes变化时同步到localStorage useEffect(() => { localStorage.setItem('react-notes', JSON.stringify(notes)); console.log('saved notes:', notes); }, [notes]);
为什么这样可行?
- 用
useState的函数式初始化,只会在组件首次挂载时执行一次,不会每次渲染都重新生成默认数组,也避免了和useEffect的执行顺序冲突。 - 优先读取
localStorage,确保页面刷新时直接加载保存的数据,而不是先显示初始数据再替换,解决了数据“消失”的问题。 - 第二个
useEffect只负责在notes变化时同步到localStorage,逻辑清晰,不会出现多余的触发。
内容的提问来源于stack exchange,提问作者ines
相关产品推荐
相关产品推荐

