Next.js13中React Context页面刷新后值重置问题求助
问题分析与解决:Next.js 13中Context状态刷新后丢失
问题根源
React Context的状态仅存储在客户端内存中,页面刷新时整个React应用会重新初始化,Context里的状态会回到定义的默认值,因此之前通过API设置的数据会丢失。另外你在子组件中直接执行await fetchApi(),会导致组件每次渲染都重复发起API请求,还可能触发不必要的状态更新。
解决方法
要保留Context状态,需将数据持久化到本地存储(如localStorage/sessionStorage),在Context初始化时从存储读取数据,状态更新时同步写入存储。同时修复子组件的API调用逻辑,避免重复请求。
步骤1:修改Context Provider,集成持久化逻辑
更新contextProvider.ts,在初始化状态时从localStorage读取值,并用useEffect监听状态变化同步到存储:
"use client"; import React, { useEffect } from "react"; import { createContext, Dispatch, SetStateAction } from "react"; interface IChildrenProp { children: React.ReactNode; } interface IAppContext { userId: number; setUserId: Dispatch<SetStateAction<number>>; userName: string; setUserName: Dispatch<SetStateAction<string>>; userEmail: string; setUserEmail: Dispatch<SetStateAction<string>>; userRole: string; setUserRole: Dispatch<SetStateAction<string>>; } export const AppContext = createContext<IAppContext>({ userId: 0, setUserId: (): number => 0, userName: "", setUserName: () => "", userEmail: "", setUserEmail: () => "", userRole: "", setUserRole: () => "", }); export const ContextProvider: React.FC<IChildrenProp> = ({ children }) => { // 从localStorage读取初始值,无数据则用默认值 const [userId, setUserId] = React.useState<number>(() => { const saved = localStorage.getItem("userId"); return saved ? parseInt(saved, 10) : 0; }); const [userName, setUserName] = React.useState<string>(() => { return localStorage.getItem("userName") || ""; }); const [userEmail, setUserEmail] = React.useState<string>(() => { return localStorage.getItem("userEmail") || ""; }); const [userRole, setUserRole] = React.useState<string>(() => { return localStorage.getItem("userRole") || ""; }); // 状态变化时同步到localStorage useEffect(() => { localStorage.setItem("userId", userId.toString()); localStorage.setItem("userName", userName); localStorage.setItem("userEmail", userEmail); localStorage.setItem("userRole", userRole); }, [userId, userName, userEmail, userRole]); return ( <AppContext.Provider value={{ userId, setUserId, userName, setUserName, userEmail, setUserEmail, userRole, setUserRole, }} > {children} </AppContext.Provider> ); };
步骤2:修复子组件的API调用逻辑
将API请求放到useEffect中,仅在初始状态下发起请求,避免重复调用:
"use client" import React, { useEffect, useContext } from "react"; import { AppContext } from "./contextProvider"; const ChildComponent = () => { const { userId, setUserId, userName, setUserName } = useContext(AppContext); console.log(userId, userName); useEffect(() => { // 仅当userId为默认值时,才发起API请求 if (userId === 0) { const fetchData = async () => { const result = await fetchApi(); if (result) { setUserId(result.id); setUserName(result.username); } }; fetchData(); } }, [userId, setUserId, setUserName]); return <div>子组件内容</div>; }; export default ChildComponent;
补充说明
- 若存储敏感信息,建议使用
sessionStorage(关闭标签页后数据自动清除),或结合后端token验证,页面刷新时先验证token再重新获取用户数据。 localStorage仅支持字符串存储,数字类型需手动转换(如userId存为字符串,读取时转数字)。
内容的提问来源于stack exchange,提问作者Abhishek Kumar
相关产品推荐
相关产品推荐

