React页面重载后localStorage存储的笔记无法持久化问题
问题排查与解决:React localStorage 页面重载后数据丢失
问题原因
- 循环覆盖逻辑:第二个
useEffect把savedNotes设为依赖项,组件初始化时savedNotes初始值为空数组,触发该effect读取localStorage数据并更新状态;但状态更新会立即触发第一个依赖savedNotes的effect,把空数组重新写入localStorage,直接覆盖之前保存的有效数据。 - 初始状态未正确初始化:
savedNotes初始值硬设为空数组,没有直接从localStorage读取数据,导致组件挂载时初始状态错误,引发后续存储逻辑异常。
解决方法
- 从localStorage直接初始化状态:在
useState初始化阶段,优先读取localStorage中的数据作为初始值,避免依赖后续effect异步加载。 - 移除错误的监听effect:删除第二个监听
savedNotes的useEffect,避免循环触发存储操作。 - 保留实时存储逻辑:第一个
useEffect监听savedNotes变化,实时将数据写入localStorage即可。
修改后的完整代码
import { useState, useEffect } from 'react' import { v4 as uuidv4 } from 'uuid'; function App() { const [count, setCount] = useState(0) const defaulttext = "Add a task..."; const [inputtext, setinputtext] = useState(defaulttext) const [note, setnote] = useState("") // 直接从localStorage读取初始值,不存在则设为空数组 const [savedNotes, setSavedNotes] = useState(() => { const saved = localStorage.getItem('sNotes'); return saved ? JSON.parse(saved) : []; }); // 监听savedNotes变化,实时存储到localStorage useEffect(() => { localStorage.setItem('sNotes', JSON.stringify(savedNotes)) }, [savedNotes]) const handlechange = (e)=>{ setinputtext(e.target.value) } const handlefocus = ()=>{ if(inputtext === defaulttext){ setinputtext('') } } const savenote = () => { const newNote = { id: uuidv4(), text: inputtext }; setSavedNotes([...savedNotes, newNote]); setinputtext(defaulttext); }; useEffect(() => { console.log(note); }, [note]); return ( <> <div className='containerr flex flex-col w-[35%] justify-center '> <div className="navbar bg-green-600 flex flex-row w-[100%] justify-between"> <span>Todo List</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" className="lucide lucide-menu"><line x1="4" x2="20" y1="12" y2="12" /><line x1="4" x2="20" y1="6" y2="6" /><line x1="4" x2="20" y1="18" y2="18" /></svg> </div> <div className='inputtext justify-self-center ml-10 mt-4 mb-4 mr-10 flex flex-row '> <input onChange={handlechange} onFocus={handlefocus} type="text" value={inputtext} className=' bg-green-300 w-full outline-none ' /> <svg onClick={savenote} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="current" stroke="black" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="lucide lucide-plus bg-green-300 w-[23px]"><path d="M5 12h14" /><path d="M12 5v14" /></svg> </div> <div className='mynotes flex flex-col bg-green-500 min-h-[400px] text-center text-xl'> <span className='bg-green-950 text-white p-3'>MyNotes</span> {savedNotes.length === 0 ? ( <div>No notes yet, add one!</div> ) : ( <div> {savedNotes.map((savednote)=>( <div key={savednote.id} className="note bg-green-200 mt-3 mb-3">{savednote.text}</div> ))} </div> )} </div> </div> </> ) } export default App
额外优化:将原有的"Loading..."提示改为更贴合场景的"No notes yet, add one!",因为初始状态已直接从localStorage读取,不存在异步加载过程。
内容的提问来源于stack exchange,提问作者Papayc
相关产品推荐
相关产品推荐

