
在React单页应用(SPA)中,当用户刷新页面时,整个应用会重新加载。这意味着所有组件的状态(包括通过useState或Context API管理的状态)都会被重置到其初始值。对于认证信息(如用户ID、访问令牌、用户角色等),如果仅将其存储在组件的内部状态或Context中,那么在页面刷新后,这些信息将丢失,导致用户需要重新登录或无法访问受保护的资源。
在提供的代码示例中,useAuth钩子内部的AuthProvider组件使用useState({})来初始化auth对象。当页面刷新时,AuthProvider会重新挂载,auth状态再次被初始化为{},即使之前用户已经登录,其id属性也会因此变为null或undefined。尽管useEffect尝试从localStorage读取数据,但原始的useEffect只在组件初次挂载时运行一次且其依赖项为空数组[]。这意味着:
为了解决上述问题,我们需要确保认证信息在auth状态发生变化时被保存到持久存储中,并在应用加载时从该存储中恢复。浏览器提供的localStorage是一个理想的客户端存储机制,适合存储非敏感的、需要长期保留的数据。
核心思路如下:
我们将对AuthProvider进行改造,使其能够正确地从localStorage读取和写入认证数据。
// src/hooks/useAuth.js (或 src/context/AuthContext.js)
import { createContext, useState, useEffect, useCallback } from "react";
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
// 1. 使用函数式初始化useState,确保在组件首次渲染时就从localStorage读取数据
const [auth, setAuth] = useState(() => {
try {
const storedToken = localStorage.getItem("accessToken");
const storedRoles = localStorage.getItem("roles");
const storedId = localStorage.getItem("userId");
// 只有当所有关键认证信息都存在时,才初始化auth对象
if (storedToken && storedRoles && storedId) {
const token = JSON.parse(storedToken);
const roles = JSON.parse(storedRoles);
const id = JSON.parse(storedId);
// 进一步校验id,确保其有效性
if (id !== null && id !== undefined) {
return { token, roles, id };
}
}
} catch (error) {
console.error("从 localStorage 解析认证数据失败:", error);
// 清除可能已损坏的 localStorage 数据
localStorage.removeItem("accessToken");
localStorage.removeItem("roles");
localStorage.removeItem("userId");
}
return {}; // 如果没有有效数据或发生错误,返回空对象作为初始状态
});
const [loading, setLoading] = useState(true); // 用于指示认证数据是否已加载完毕
// 2. 使用 useEffect 监听 auth 状态的变化,并将其同步保存到 localStorage
useEffect(() => {
// 只有当 auth 包含有效的 token, roles 和 id 时才进行保存
if (auth.token && auth.roles && auth.id) {
localStorage.setItem("accessToken", JSON.stringify(auth.token));
localStorage.setItem("roles", JSON.stringify(auth.roles));
localStorage.setItem("userId", JSON.stringify(auth.id));
} else {
// 如果 auth 状态为空(例如,用户登出),则清除 localStorage 中的认证数据
localStorage.removeItem("accessToken");
localStorage.removeItem("roles");
localStorage.removeItem("userId");
}
// 无论是否成功加载或保存,一旦完成处理,设置 loading 为 false
setLoading(false);
}, [auth]); // 依赖项为 auth,确保 auth 每次变化时都执行此 effect
// 登出功能:清除 auth 状态,并自动触发 useEffect 清除 localStorage
const logout = useCallback(() => {
setAuth({});
}, []);
return (
<AuthContext.Provider value={{ auth, setAuth, loading, logout }}>
{children}
</AuthContext.Provider>
);
};
export default AuthContext;代码解释:
在消费useAuth钩子的组件中,我们需要确保在auth.id可用时才执行依赖于它的操作。这通常意味着要检查loading状态。
// src/components/Exercises/Exercises.js
import React, { useState, useEffect } from "react";
import { useParams, useNavigate } from "react-router-dom";
import styles from "./ExercisePage.module.css";
import api from "../../apis/requestService";
import useAuth from "../../hooks/useAuth"; // 确保路径正确
function Exercises() {
const { auth, loading } = useAuth(); // 引入 loading 状态
const { id } = useParams();
const navigate = useNavigate();
const [requests, setRequests] = useState([]);
const [exerciseData, setExerciseData] = useState({
weight: "",
reps: "",
exerciseId: id,
date: null,
});
const [err, setErr] = useState("");
const [popupStyle, showPopup] = useState("hide");
const { weight, reps } = exerciseData;
useEffect(() => {
setExerciseData((prevData) => ({
...prevData,
exerciseId: id,
date: new Date(),
}));
// 只有当认证数据加载完成且 auth.id 存在时才发起请求
if (!loading && auth.id) {
api.getUserExercises(id).then((response) => {
setRequests(response.data);
}).catch(error => {
console.error("获取用户运动数据失败:", error);
setErr("无法加载运动数据。");
popup();
});
}
}, [id, auth.id, loading]); // 添加 loading 到依赖项
const onInputChange = (e) => {
setExerciseData({ ...exerciseData, [e.以上就是React应用中刷新页面后认证信息丢失的解决方案的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号