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

React Redux Store未更新,登录状态切换功能异常求助

问题:React Redux登录状态更新后无法获取最新值,无法切换Header显示内容

我希望实现:用户未登录时,页面Header显示登录和注册链接;用户登录后,显示登出链接。通过React Redux存储用户登录状态,登录/登出时调用dispatch更新状态。调试发现action和reducer参数传递正常,但获取Store值时始终显示旧值,无法实现状态切换。


相关代码

Login组件代码

import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom';
import Footer from '../footer/Footer';
import "./Login.css";
import { setUser } from '../../actions/index';
import { useDispatch } from 'react-redux';
import store  from '../../store';

const Login = () => {
  const state = store.getState();
  const userdata = Object.values(state);
   
  const sendUserstatus = useDispatch();

  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleEmailChange = (event) => {
    setEmail(event.target.value);
  }

  const handlePasswordChange = (event) => {
    setPassword(event.target.value);
  }

  const navigate = useNavigate();

  const handleSubmit = async (event) => {
    event.preventDefault();
    const res = await fetch("/signin", {
      method: "POST",
      headers: {
        "content-Type": "application/json"
      },
      body: JSON.stringify({
        email,
        password
      })
    })
    const data = res.json();
    if (res.status === 400 || !data) {
      window.alert("invalid Credentials");
    } else {
      sendUserstatus(setUser(true));
      console.log(userdata, "login successful");

      window.alert("Login Successful");
      navigate("/")
    }
  }
  return (
    <>
      <form method='POST' onSubmit={handleSubmit} className="login-form">
        <label className="login-label">
          Email:
          <input
            type="email"
            value={email}
            onChange={handleEmailChange}
            className="login-input"
          />
        </label>
        <br />
        <label className="login-label">
          Password:
          <input
            type="password"
            value={password}
            onChange={handlePasswordChange}
            className="login-input"
          />
        </label>
        <br />
        <a href="#sfsd" className="forgot-password-link">Forgot password?</a>
        <br />
        <button type="submit" className="login-button">Login</button>
      </form>
      <Footer></Footer>
    </>
  )
}

export default Login

Reducer代码

const initialdata = false;

export const truefalse = (state = initialdata, action) => {
  switch(action.type) {
    case "SET_TRUE":
      return state = true;

    case "SET_FALSE":
      return state = false;

    default:
      return state;
  }
}

var wpmdata = 0;

export const setWpm = (state = wpmdata, action) => {
  switch(action.type) {
    case"SET_WPM":
      return wpmdata = action.paylod;

    default:
      return wpmdata;
  }
}

var Accuracy = 0;

export const setAccuracy = (state = Accuracy, action) => {
  switch(action.type) {
    case"SET_ACCURACY":
      return Accuracy = action.Accuracy;

    default:
      return Accuracy;
  }
}

var userStatus = null;

export const setUser = (state = userStatus, action) => {
  switch(action.type){
    case "SET_USER":
      return userStatus = action.userStatus;

    default: return userStatus;
  }
}

var Toggle = null;

export const setToggle = (state = Toggle, action) => {
  switch(action.type) {
    case "TOGGLE":
      return Toggle = action.Toggle

    default:
      return Toggle
  }
}

Actions代码

export const setTrue = () => {
  return {
    type: "SET_TRUE",
  }
}

export const setFalse = () => {
  return {
    type: "SET_FALSE",
  }
}

export const setWpm = (val) => {
  return {
    type: "SET_WPM",
    paylod: val
  }
}

export const setAccuracy = (val) => {
  return {
    type: "SET_ACCURACY",
    Accuracy: val
  }
}

export const setUser = (val) => {
  console.log(val, "afsdf");
  return {
    type: "SET_USER",
    userStatus: val
  }
}

export const setToggle = (val) => {
  return {
    type: "TOGGLE",
    Toggle: val
  }
}

Root Reducer代码

import {
  truefalse,
  setAccuracy,
  setWpm,
  setUser,
  setToggle
} from "./typingtestReducer";
import { combineReducers } from "redux";

const rootReducer = combineReducers({
  truefalse,
  setWpm,
  setAccuracy,
  setUser,
  setToggle
})

export default rootReducer

核心问题分析

  • 直接调用store.getState()无法响应状态更新:组件初始化时仅执行一次store.getState(),后续Redux状态变化不会触发组件重新渲染,导致获取的始终是旧值。
  • Reducer违反纯函数原则:所有reducer依赖全局变量并直接修改,Redux无法检测到状态变化(Redux要求reducer必须返回新状态值,不能修改外部状态)。
  • 状态更新后立即打印旧值:dispatch是异步更新操作,调用后立即打印状态时,更新尚未完成。

修复方案

1. 用useSelector替代直接调用store.getState()

使用React-Redux的useSelector钩子订阅状态变化,组件会在状态更新时自动重新渲染并获取最新值:

// 修改Login组件
import { useDispatch, useSelector } from 'react-redux';

const Login = () => {
  // 获取最新用户状态
  const userStatus = useSelector(state => state.setUser);
  const sendUserstatus = useDispatch();

  // ...其他代码

  // 监听状态变化打印最新值
  React.useEffect(() => {
    console.log('当前用户状态:', userStatus);
  }, [userStatus]);
}

2. 修复Reducer,遵循纯函数规则

移除全局变量,直接使用state参数,返回新状态值:

// 修正后的setUser reducer
export const setUser = (state = null, action) => {
  switch(action.type){
    case "SET_USER":
      return action.userStatus;
    default: 
      return state;
  }
}

// 其他reducer同理修改
export const truefalse = (state = false, action) => {
  switch(action.type) {
    case "SET_TRUE":
      return true;
    case "SET_FALSE":
      return false;
    default:
      return state;
  }
}

export const setWpm = (state = 0, action) => {
  switch(action.type) {
    case "SET_WPM":
      return action.payload; // 修正拼写错误:paylod → payload
    default:
      return state;
  }
}

3. 修正Action中的拼写错误

// 修正setWpm action的payload拼写
export const setWpm = (val) => {
  return {
    type: "SET_WPM",
    payload: val
  }
}

4. Header组件中实现状态切换显示

import { useSelector, useDispatch } from 'react-redux';
import { setUser } from '../actions/index';

const Header = () => {
  const userStatus = useSelector(state => state.setUser);
  const dispatch = useDispatch();

  const handleLogout = () => {
    dispatch(setUser(false));
  }

  return (
    <header>
      {!userStatus ? (
        <>
          <a href="/login">登录</a>
          <a href="/register">注册</a>
        </>
      ) : (
        <button onClick={handleLogout}>登出</button>
      )}
    </header>
  );
}

内容的提问来源于stack exchange,提问作者Dheeraj Kumar Yadav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 02:50:03