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

React AuthContext中直接访问与函数获取AuthService状态结果不一致

问题解决:React AuthContext状态更新异常

问题现象

调用AuthService类的logInAsGuest函数后,直接打印authUser对象显示isLogin已变为true,但通过authUser.currentUser()获取的isLogin仍为false,同时组件不会根据状态变化重新渲染。

核心原因

  1. React的useState仅在初始渲染时创建AuthService实例的引用,后续直接修改实例内部的this.state,React无法检测到引用变化,不会触发组件重新渲染。
  2. 类实例内部的状态修改没有同步到React的状态管理中,导致isLogin等状态无法在组件中正确更新。

解决方案

将用户认证状态移至AuthProvider的useState中管理,让AuthService作为无状态的工具类,仅负责处理认证逻辑并触发状态更新,确保React能正确感知状态变化。

修改后的代码

1. AuthProvider.js

import React, { createContext, useState, useContext } from "react";
import AuthService from "./AuthService";

const AuthContext = React.createContext();

export function useAuth() {
  return useContext(AuthContext);
}

export function AuthProvider(props) {
  // 将认证状态放在React的useState中管理
  const [authState, setAuthState] = useState({
    admin: false,
    jwt: "",
    email: "",
    username: "",
    isLogin: false,
  });

  // 初始化AuthService,传入状态更新函数
  const authService = new AuthService(setAuthState);

  const value = {
    authState,
    authService,
    isLogin: authState.isLogin,
  };

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

2. AuthService.js

const axios = require("axios").default;
axios.defaults.baseURL = "http://localhost:1337/api";

class AuthService {
  constructor(setAuthState) {
    // 接收React的状态更新函数
    this.setAuthState = setAuthState;
  }

  LogInAsGuest() {
    console.log("Logging in as guest... Auth context");
    // 通过setAuthState更新React状态
    this.setAuthState({
      admin: false,
      jwt: "",
      email: "",
      username: "",
      isLogin: true,
    });
  }

  logOut() {
    this.setAuthState({
      admin: false,
      jwt: "",
      email: "",
      username: "",
      isLogin: false,
    });
  }

  // 示例:登录接口调用
  async LogIn(credentials) {
    try {
      const response = await axios.post("/auth/local", credentials);
      const { jwt, user } = response.data;
      this.setAuthState({
        admin: user.admin,
        jwt,
        email: user.email,
        username: user.username,
        isLogin: true,
      });
    } catch (error) {
      console.error("登录失败:", error);
    }
  }
}

export default AuthService;

3. Home.js(修改状态引用)

import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { useEffect, useState } from "react";
import Login from "./login";
import ClientPage from "./client";
import Dashboard from "./admin";
import fetchUrl from "./fetch";
import { useAuth } from "./Auth/AuthProvider";

export default function Home() {
  const [title, setTitle] = useState("Login duls Kang");
  const [version, setVersion] = useState("1.0.0");
  const { authState, authService, isLogin } = useAuth();

  useEffect(() => {
    console.log("认证状态变化:", authState);
  }, [authState]);

  return (
    <div>
      <Head>
        <title>{title}</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <div className="relative w-full pt-[5%] pb-[2%] h-screen min-h-fit flex flex-col items-center justify-start">
        <div className="absolute w-[30%] md:w-[10%] min-h-fit text-[3.7vw] md:text-[1.4vw] left-[2%] top-[2%] flex flex-col justify-start items-start">
          <div className="aspect-[20/5] w-[100%] left-[2%] top-[2%]">
            Testing: {version}
          </div>
          <div className="aspect-[20/5] w-[100%] left-[2%] top-[6%]">
            Auth? &nbsp;&nbsp;: {authState.admin ? "Admin" : "Client"}
          </div>
          <div className="aspect-[20/5] rounded-[5%/15%] flex justify-center items-center w-[100%] left-[2%] top-[10%] bg-[purple] text-[white]">
            <button
              onClick={() => authService.logOut()}
              className="w-full h-full"
            >
              LogOut
            </button>
          </div>
        </div>

        <div className="w-[85%] md:w-[40%] mt-[25%] md:mt-[0%] min-h-fit h-screen bg-[grey] rounded-[2%/2%] flex flex-col items-center justify-start overflow-y-scroll">
          {!isLogin && <Login></Login>}
          {isLogin && authState.admin && <Dashboard auth={authState} />}
          {isLogin && !authState.admin && <ClientPage />}
        </div>
        <div className="aspect-[200/50] w-[40%] bg-[white]"></div>
      </div>
    </div>
  );
}

4. Login.js(修改调用方式)

import { useState } from "react";
import { useAuth } from "./Auth/AuthProvider";

const Login = () => {
  const [credential, setCredential] = useState({ username: "", password: "" });
  const { authService, isLogin } = useAuth();

  return (
    <>
      <div className="flex flex-col text-[3.75vw] md:text-[1.25vw] justify-start gap-[6%] items-center w-[100%] h-[70%]">
        <div className="aspect-[200/35] w-[100%] bg-[lightgrey] text-center text-[6vw] md:text-[2vw] flex justify-center items-center rounded-[2%/10%]">
          Login duls Bray
        </div>
        <div className="relative aspect-[200/30] md:aspect-[200/20] w-[70%] bg-[green] rounded-[2%/12%]">
          <input
            className="absolute w-full h-full p-[5%] rounded-[2%/12%]"
            placeholder="username"
            onChange={(e) => {
              setCredential({
                ...credential,
                username: e.target.value,
              });
            }}
          />
        </div>
        <div className="relative aspect-[200/30] md:aspect-[200/20] w-[70%] bg-[green] rounded-[2%/12%]">
          <input
            className="absolute w-full h-full p-[5%] rounded-[2%/12%]"
            type="password"
            placeholder="password"
            onChange={(e) => {
              setCredential({
                ...credential,
                password: e.target.value,
              });
            }}
          />
        </div>
        <div className="relative aspect-[200/30] md:aspect-[200/20] w-[70%] bg-[green] rounded-[2%/12%]">
          <button
            onClick={async () => {
              const { username, password } = credential;
              setCredential({
                username: "",
                password: "",
              });
              await authService.LogIn({
                identifier: username,
                password: password,
              });
            }}
            className="absolute w-full h-full rounded-[2%/12%] hover:bg-[lightgreen] active:bg-[green]"
          >
            Login
          </button>
        </div>
        <div className="relative aspect-[200/30] md:aspect-[200/20] w-[70%] bg-[green] rounded-[2%/12%]">
          <button
            onClick={() => {
              console.log("Logging in as guest...");
              authService.LogInAsGuest();
            }}
            className="absolute w-full h-full rounded-[2%/12%] hover:bg-[lightgreen] active:bg-[green]"
          >
            Log in as client
          </button>
        </div>
      </div>
    </>
  );
};

export default Login;

关键说明

  • 把认证状态从AuthService类内部移到AuthProvider的useState中,确保React能检测到状态变化并触发组件重新渲染。
  • AuthService不再存储状态,而是通过接收setAuthState函数来更新React管理的状态,实现状态同步。
  • 组件中直接使用AuthProvider提供的authState和isLogin,无需调用currentUser()方法,状态更新会自动同步到所有消费组件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:46:01