You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用useMemo与useEffect实现认证时的状态更新问题排查

认证实践确认与代码修复

一、认证最佳实践解答

  • 登录状态检查:不建议每个页面单独检查,推荐用路由守卫统一处理(比如React Router中通过Outlet和导航拦截),对需要权限的路由统一校验未登录状态,自动跳转到登录页,避免重复代码。
  • Token管理:登录时存储Token、登出时移除Token是标准且合理的实践。注意:
    • 若用Cookie存储,建议后端设置HttpOnly和Secure属性,防范XSS攻击;
    • 若用localStorage,要注意XSS风险,需额外做前端防护。
  • 状态同步:登录/登出时必须同步更新全局上下文的登录状态,确保所有依赖该状态的组件能实时响应变化。

二、代码问题修复

你的代码存在几个关键问题导致loggedIn状态无法正常更新,以下是修复后的完整方案:

修复点说明

  1. Token获取时机修正:原代码中Token在组件外部初始化,仅执行一次,登录后Cookie更新但Token变量不会同步,改为在需要时直接从Cookie获取最新值。
  2. useEffect依赖修正:原依赖loggedIn会导致无限循环,改为空数组仅在组件挂载时验证一次登录状态。
  3. Context值补充:将loggedIn状态加入Context的value中,让子组件可以直接获取登录状态。
  4. useMemo依赖修正:添加login、logout、loggedIn到依赖数组,确保Context值更新时同步。
  5. 登录/登出逻辑优化:登录时正确处理异步请求,登出时将loggedIn设为false(null用于初始加载状态)。

修复后的代码

import { createContext, useContext, useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import Cookies from "universal-cookie";

const cookies = new Cookies();
const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [loggedIn, setLoggedIn] = useState(null); // null: 加载中, true: 已登录, false: 未登录
  const navigate = useNavigate();

  // 页面挂载时验证登录状态
  useEffect(() => {
    const validateAuth = async () => {
      const token = cookies.get("TOKEN");
      if (!token) {
        setLoggedIn(false);
        return;
      }

      try {
        await axios.get("http://localhost:3005/auth-endpoint", {
          headers: { Authorization: `Bearer ${token}` },
        });
        setLoggedIn(true);
      } catch (error) {
        setLoggedIn(false);
        cookies.remove("TOKEN", { path: "/" }); // 无效Token清空Cookie
      }
    };

    validateAuth();
  }, []);

  const login = async (data) => {
    try {
      const result = await axios.post("http://localhost:3005/login", {
        email: data.email,
        password: data.password,
      });
      cookies.set("TOKEN", result.data.token, { path: "/" });
      setLoggedIn(true);
      navigate("/dashboard/profile", { replace: true });
    } catch (error) {
      // 可添加错误提示逻辑,比如设置错误状态给组件展示
      console.error("登录失败:", error.response?.data || error.message);
    }
  };

  const logout = () => {
    setLoggedIn(false);
    cookies.remove("TOKEN", { path: "/" });
    navigate("/", { replace: true });
  };

  const value = useMemo(
    () => ({
      loggedIn,
      login,
      logout,
    }),
    [loggedIn, login, logout]
  );

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

export const useAuth = () => {
  return useContext(AuthContext);
};

三、使用示例

在需要校验登录状态的组件中,通过useAuth获取状态:

import { useAuth } from "./AuthProvider";

const ProfilePage = () => {
  const { loggedIn } = useAuth();

  if (loggedIn === null) {
    return <div>加载中...</div>;
  }

  if (!loggedIn) {
    // 建议配合路由守卫统一处理跳转,无需手动判断
    return <div>请先登录</div>;
  }

  return <div>个人资料页</div>;
};

内容的提问来源于stack exchange,提问作者lastoix61

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:45:44