React.js中全局单例对象导出异常问题:如何确保LoggedUser实例全局唯一
你遇到的核心问题是页面刷新导致内存中的单例实例被重置。当你调用window.location.href = "/adminPanel"时,浏览器会重新加载整个页面,之前JavaScript内存中的所有数据(包括你的loggedUser实例)都会被清空。新页面加载时,会重新导入logged_user.js,创建一个全新的实例,自然email就是初始的null了。
另外,先提个你代码里的小bug:resetUser方法里把#userExist设为true,这明显不符合逻辑,应该改为false:
resetUser(){ this.#email = null; this.#userExist = false; // 这里修正为false }
接下来给你两种针对性的解决方案:
方案一:用前端路由跳转(不刷新页面)
如果你的项目使用了React Router这类前端路由库,替换掉window.location.href的跳转方式,这样页面不会刷新,内存中的单例会完整保留:
函数组件示例(React Router v6+)
import { useNavigate } from 'react-router-dom'; // 在组件内初始化导航方法 const navigate = useNavigate(); // 登录成功后替换原跳转逻辑 .then(() => { this.setState({ loading: false }); this.showAlert("Signed In.", false); loggedUser.setUser(this.state.emailInput); navigate("/adminPanel"); // 用路由跳转替代页面刷新 })
类组件示例
如果是类组件,可以通过withRouter高阶组件或者props获取history对象:
// 登录成功后 .then(() => { // ...其他逻辑 this.props.history.push("/adminPanel"); })
这种方式下,应用状态(包括你的loggedUser实例)会全程保留,管理页面导入的就是同一个实例,能正确获取到邮箱。
方案二:持久化存储用户信息(支持页面刷新)
如果需要支持页面刷新后依然保留用户状态,你可以把邮箱存储到localStorage或sessionStorage中,让LoggedUser初始化时自动读取存储的值:
修改logged_user.js:
class LoggedUser{ #email; #userExist; constructor(){ // 初始化时从localStorage读取已存储的邮箱 const savedEmail = localStorage.getItem('loggedUserEmail'); this.#email = savedEmail || null; this.#userExist = !!savedEmail; // 有存储值则标记用户已登录 } setUser(email){ this.#email = email; this.#userExist = true; // 将邮箱存入localStorage持久化 localStorage.setItem('loggedUserEmail', email); } resetUser(){ this.#email = null; this.#userExist = false; // 清除存储的用户信息 localStorage.removeItem('loggedUserEmail'); } get userExist(){ return this.#userExist; } get email(){ return this.#email; } } const loggedUser = new LoggedUser(); export default loggedUser;
这样就算页面刷新,LoggedUser实例初始化时会自动从localStorage读取之前存储的邮箱,管理页面就能正确获取到值了。
最后还要注意:确保所有导入loggedUser的文件使用完全一致的相对路径,比如所有地方都用import loggedUser from './logged_user.js',避免路径差异导致模块被重复加载(ES模块默认会缓存,但路径不一致可能被识别为不同模块)。
内容的提问来源于stack exchange,提问作者Ashutosh Aswal

