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

React Context无法更新默认值:登录后状态始终为0求助

问题描述

我开发了一个登录表单,登录成功后尝试将React Context的值设置为1,但userStatus始终保持默认值0,即使硬编码设置也没有任何变化。

相关登录逻辑代码:

import { UserStatus, useUserStatus } from "../context/context";

const completeLoginAction = async (credentials: any) => {
  var loginSuccess = await authService.login(credentials);
  if (loginSuccess) {
    setUserStatus(1);
    localStorage.setItem("userStatus", JSON.stringify(userStatus));
    console.log("USERSTATIS AFTER LOGIN IS" + userStatus);
    console.log(
      "local storage on login is " + localStorage.getItem("userStatus")
    );
    return true;
  } else {
    return false;
  }
};

context.tsx代码:

import { createContext, useContext } from "react";

export enum UserStatus {
  LoggedOff = 0,
  LoggedIn = 1,
  UserStatus,
}

export type UserStatusContextType = {
  userStatus: UserStatus;
  setUserStatus: (userStatus: UserStatus) => void;
};

export const UserStatusContext = createContext<UserStatusContextType>({
  userStatus: UserStatus.LoggedOff,
  setUserStatus: (userStatus) => console.warn("log on status unknown"),
});

export const useUserStatus = () => useContext(UserStatusContext);

完整登录表单组件代码:

import React, { useContext, useEffect, useState } from "react";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import "bootstrap/dist/css/bootstrap.min.css";
import "./LoginPage.css";
import authService from "../../services/authService";
import { Navigate, useNavigate } from "react-router-dom";
import { UserStatus, useUserStatus } from "../context/context";

const LoginPage = () => {
  const [username, setUserName] = useState("");
  const [password, setPassword] = useState("");
  const [errMsg, setErrMsg] = useState("");
  const [sucess, setSuccess] = useState("");

  const { userStatus, setUserStatus } = useUserStatus();

  const navigate = useNavigate();

  const handleUsernameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setUserName(e.target.value);
  };

  const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setPassword(e.target.value);
  };

  const handleSave = async (e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault();

    const credentials = {
      Username: username,
      Password: password,
    };

    var completed = await completeLoginAction(credentials);

    // if (completed) {
    //   console.log("logged in");
    //   navigate("/");
    // } else {
    //   showErrorMessage();
    // }
  };

  const completeLoginAction = async (credentials: any) => {
    var loginSuccess = await authService.login(credentials);
    if (loginSuccess) {
      setUserStatus(1);
      localStorage.setItem("userStatus", JSON.stringify(userStatus));
      console.log("USERSTATIS AFTER LOGIN IS" + userStatus);
      console.log(
        "local storage on login is " + localStorage.getItem("userStatus")
      );
      return true;
    } else {
      return false;
    }
  };

  const showErrorMessage = () => {
    let elms = document.getElementsByClassName(
      "loginfailmessage"
    ) as HTMLCollectionOf<HTMLElement>;

    for (var i = 0; i < elms.length; i++) {
      elms[i].style.display = "block";
    }
  };

  return (
    <div className="container">
      <div className="LoginForm">
        <h1 className="Title">Login</h1>
        <Form>
          <Form.Group className="mb-3" controlId="formBasicEmail">
            <Form.Label>Username</Form.Label>
            <Form.Control
              type="text"
              placeholder="Enter username"
              onChange={handleUsernameChange}
              name="username"
              required
            />
          </Form.Group>

          <Form.Group className="mb-3" controlId="formBasicPassword">
            <Form.Label>Password</Form.Label>
            <Form.Control
              type="password"
              placeholder="Password"
              onChange={handlePasswordChange}
              name="password"
              required
            />
          </Form.Group>
          <Button variant="primary" type="submit" onClick={handleSave}>
            Submit
          </Button>
        </Form>
        <h4 className="loginfailmessage" style={{ display: "none" }}>
          Failed to login
        </h4>
      </div>
    </div>
  );
};

export default LoginPage;
解决思路

1. 补全Context Provider配置

你只创建了Context,但没有在组件树的上层使用UserStatusContext.Provider包裹需要访问Context的组件。没有Provider的情况下,useUserStatus会一直使用Context的默认值,调用setUserStatus只会触发默认的警告函数,根本不会更新状态。

在根组件(比如App.tsx)中添加Provider:

import { useState } from 'react';
import { UserStatusContext, UserStatus } from './context/context';
import LoginPage from './LoginPage';

function App() {
  const [userStatus, setUserStatus] = useState<UserStatus>(UserStatus.LoggedOff);

  return (
    <UserStatusContext.Provider value={{ userStatus, setUserStatus }}>
      {/* 此处放置路由或其他需要访问Context的组件 */}
      <LoginPage />
    </UserStatusContext.Provider>
  );
}

export default App;

2. 处理React状态更新的异步特性

setUserStatus是异步操作,调用后立刻读取userStatus拿到的还是更新前的旧值,所以你看到的console.log输出默认值是正常现象。

要将最新值同步到localStorage,有两种方案:

方案一:直接使用目标值存储

const completeLoginAction = async (credentials: any) => {
  var loginSuccess = await authService.login(credentials);
  if (loginSuccess) {
    const newStatus = UserStatus.LoggedIn;
    setUserStatus(newStatus);
    localStorage.setItem("userStatus", JSON.stringify(newStatus));
    console.log("USERSTATIS AFTER LOGIN IS" + newStatus);
    return true;
  } else {
    return false;
  }
};

方案二:用useEffect监听状态变化

在LoginPage组件中添加监听,每次userStatus更新时自动同步到localStorage:

useEffect(() => {
  localStorage.setItem("userStatus", JSON.stringify(userStatus));
}, [userStatus]);

3. 规范枚举值的使用

你的UserStatus枚举已经定义了LoggedIn = 1,直接使用枚举值比硬写数字更清晰,也避免出错:

setUserStatus(UserStatus.LoggedIn); // 替代setUserStatus(1)

另外,枚举中多余的UserStatus成员建议删除:

export enum UserStatus {
  LoggedOff = 0,
  LoggedIn = 1,
}

4. 确保localStorage读取逻辑正确

后续读取localStorage时,记得解析JSON:

const savedStatus = localStorage.getItem("userStatus");
if (savedStatus) {
  const parsedStatus = parseInt(savedStatus, 10);
  // 可在根组件useState中用该值初始化Context状态
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:25:19