页面刷新后useState丢失localStorage数据,如何解决?
解决页面刷新后localStorage数据无法正常读取的问题
你的代码存在几个核心问题,导致刷新后state无法正确获取localStorage中的数据,下面是具体修复方案:
1. 直接用localStorage初始化state
组件挂载时,useState的初始值应该直接从localStorage读取,而不是等到useEffect执行后再设置。这样初始渲染阶段就能拿到数据,不用依赖异步的state更新。
示例修改:
const [userId, setUserId] = useState<string>( JSON.parse(localStorage.getItem("userId") as string) || "" ); const [results, setResults] = useState<boolean>(localStorage.length > 0); const [studentEnglishResults, setStudentEnglishResults] = useState<{ [key: string]: string; }>( JSON.parse(localStorage.getItem("englishAnswers") as string) || {} ); const [englishResults, setEnglishResults] = useState<string[]>( Object.keys(JSON.parse(localStorage.getItem("englishAnswers") as string) || {}) );
2. 修复useEffect里的异步state更新问题
你原代码中在useEffect里设置完state后立刻console.log,但React的state更新是异步的,此时打印的还是旧值。另外setEnglishResults(Object.keys(studentEnglishResults))里的studentEnglishResults还是初始空对象,因为setStudentEnglishResults还未完成更新。
正确做法是直接使用从localStorage读取的原始值:
useEffect(() => { const storedUserId = JSON.parse(localStorage.getItem("userId") as string); const storedEnglishAnswers = JSON.parse(localStorage.getItem("englishAnswers") as string); if (localStorage.length > 0) { setUserId(storedUserId); setResults(true); setStudentEnglishResults(storedEnglishAnswers); setEnglishResults(Object.keys(storedEnglishAnswers)); } else { setResults(false); setUserId(""); setStudentEnglishResults({}); setEnglishResults([]); } // 要打印最新值直接用本地变量 console.log(storedUserId); console.log(storedEnglishAnswers); console.log(Object.keys(storedEnglishAnswers)); }, []);
3. 给依赖userId的useEffect添加正确依赖项
原代码中查找用户的useEffect没有依赖userId,刷新时userId还是初始空字符串,导致找不到用户。需要把userId加入依赖数组,这样userId更新后会重新执行查找逻辑:
useEffect(() => { const userFound = users.find((user) => user.userId === userId); if (userFound) { console.log(userFound); } else { console.log("user not found"); } }, [userId]);
完整修改后的代码
const Admin = () => { const { adminId } = useParams(); const navigate = useNavigate(); // 直接从localStorage初始化state const [userId, setUserId] = useState<string>( JSON.parse(localStorage.getItem("userId") as string) || "" ); const [results, setResults] = useState<boolean>(localStorage.length > 0); const [studentEnglishResults, setStudentEnglishResults] = useState<{ [key: string]: string; }>( JSON.parse(localStorage.getItem("englishAnswers") as string) || {} ); const [englishResults, setEnglishResults] = useState<string[]>( Object.keys(JSON.parse(localStorage.getItem("englishAnswers") as string) || {}) ); const adminUser = adminUsers.find( (adminUser) => adminUser.adminId === adminId ); useEffect(() => { if (adminUser?.adminId !== adminId) { navigate("/"); return; } }, [adminUser, adminId, navigate]); useEffect(() => { const storedUserId = JSON.parse(localStorage.getItem("userId") as string); const storedEnglishAnswers = JSON.parse(localStorage.getItem("englishAnswers") as string); if (localStorage.length > 0) { setUserId(storedUserId); setResults(true); setStudentEnglishResults(storedEnglishAnswers); setEnglishResults(Object.keys(storedEnglishAnswers)); } else { setResults(false); setUserId(""); setStudentEnglishResults({}); setEnglishResults([]); } }, []); useEffect(() => { const userFound = users.find((user) => user.userId === userId); if (userFound) { console.log(userFound); } else { console.log("user not found"); } }, [userId]); const generateResult = () => {}; const clearResult = () => { localStorage.clear(); // 清空localStorage后同步更新state setResults(false); setUserId(""); setStudentEnglishResults({}); setEnglishResults([]); }; const backToLogin = () => { navigate("/"); }; return ( <> <div className="bg-gray-400 mx-auto w-3/4 p-3 mt-5"> <p className="capitalize font-serif text-center"> <span className="font-bold uppercase text-white text-2xl"> student result checker </span> </p> </div> <div className="my-10 flex justify-center gap-3 text-white"> <button type="button" className="btn bg-green-500" onClick={generateResult} > Generate Results </button> <button type="button" className="btn bg-blue-500" onClick={backToLogin}> Login </button> </div> {results ? ( <div> <div className="shadow-md shadow-gray-500 w-2/4 mx-auto p-5"> <p className="text-2xl text-gray-500">Answers selected by: </p> <table className="table-auto border-collapse border w-full"> <thead> <tr> <th className="text-left">Question</th> <th className="text-left">Answer</th> </tr> </thead> <tbody> {englishResults.map((item, index) => { return ( <tr key={index}> <td className="">{item}</td> <td>{studentEnglishResults[item]}</td> </tr> ); })} </tbody> </table> </div> <div className="w-2/4 mx-auto mt-5 p-5"> <button type="button" className="btn bg-red-600 text-white" onClick={clearResult} > Clear Results </button> </div> </div> ) : ( <div className="w-2/4 bg-gray-400 p-5 mx-auto rounded-md"> <p className="text-4xl text-white text-center"> There is no result to display </p> </div> )} </> ); }; export default Admin;
额外说明:
- 给第一个useEffect补充了
adminUser、adminId、navigate依赖,避免ESLint警告 - 在
clearResult函数中,清空localStorage后同步更新了所有state,保证UI和数据状态一致 - 修复了
mt-50的错误(Tailwind无该类),改为mt-5
内容的提问来源于stack exchange,提问作者Misbahu Abubakar
相关产品推荐
相关产品推荐

