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

Redux报错Actions must be plain objects无法存储用户数据求助

问题根因

你遇到的Actions must be plain objects. Use custom middleware for async actions报错由3个核心原因导致:

  1. 命名冲突:登录组件中自定义的异步登录请求函数与从userSlice导入的login action重名,导致dispatch(login())实际传入的是异步函数而非Redux要求的普通对象类型action,直接触发报错。
  2. 异步时序错误:你尝试先更新React本地状态再同步到Redux,但React状态更新是异步的,setState执行后立刻dispatch拿到的还是旧值,同步到Redux的数据始终是初始值。
  3. 数据结构嵌套错误:传给login action的参数每个字段额外套了一层对象,和slice定义的state结构不匹配,就算数据存进去也无法正确读取。

代码修改方案

1. features/user.js 补全导入(你原有代码漏了createSlice导入,先补上:

import { createSlice } from '@reduxjs/toolkit'

export const userSlice = createSlice({
  name: "user",
  initialState: {
    value: { name: "", id: 0, email: "", loginId: "" },
  },
  reducers: {
    login: (state, action) => {
      state.value = action.payload;
    },
  },
});

export const { login } = userSlice.actions;
export default userSlice.reducer;

2. login_component.js 核心修改:

  • 重命名本地登录请求函数避免和导入的login action重名,请求成功后直接dispatch,不需要先存本地状态避免异步时序问题:
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useDispatch } from "react-redux";
import { login } from "../features/user";

function Login() {
  const [LoginID, setLoginID] = useState("");
  const [Password, setPassword] = useState("");
  const [LoginStatus, setLoginStatus] = useState("");

  axios.defaults.withCredentials = true;
  const dispatch = useDispatch();

  // 重命名本地登录请求函数,避免和导入的login action重名
  const handleLoginRequest = () => {
    axios
      .post("http://localhost:8000/login", {
        LoginID: LoginID,
        Password: Password,
      })
      .then((response) => {
        if (response.data.message) {
          setLoginStatus(response.data.message);
        } else {
            const userInfo = response.data.result[0];
            setLoginStatus(userInfo.UserFullName);
            // 请求成功后直接同步到Redux,不需要先存本地状态
            dispatch(login({
              name: userInfo.UserFullName,
              id: userInfo.UserID,
              email: userInfo.UserEmailID,
              loginId: userInfo.LoginID
            }))
        }
      });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    handleLoginRequest();
  };

  useEffect(() => {
    axios.get("http://localhost:8000/login").then((response) => {
      if (response.data.loggedIn === true) {
        const userInfo = response.data.user[0];
        setLoginStatus(userInfo.UserFullName);
        // 页面刷新后如果已经登录,同步用户信息同步到Redux
        dispatch(login({
          name: userInfo.UserFullName,
          id: userInfo.UserID,
          email: userInfo.UserEmailID,
          loginId: userInfo.LoginID
        }))
      }
    });
  }, [dispatch]);

  return (
    <div className="App">
      <div className="auth-wrapper">
        <div className="auth-inner">
          <form onSubmit={handleSubmit}>
            <h3>Log In</h3>

            <div className="form-group ">
              <label>Login ID</label>
              <input
                type="text"
                className="form-control"
                placeholder="Login ID"
                onChange={(e) => setLoginID(e.target.value)}
              />
            </div>

            <div className="form-group">
              <label>Password</label>
              <input
                type="password"
                className="form-control"
                placeholder="Password"
                onChange={(e) => setPassword(e.target.value)}
              />
            </div>

            <button className="btn btn-primary btn-block" type="submit">
              Login
            </button>
          </form>
          <h1>{LoginStatus}</h1>
        </div>
      </div>
    </div>
  );
}

export default Login;

3. nav_component.js 冗余导入和显示逻辑修改:

删除无用的user导入,把class属性改为React规范的className,调整显示字段为用户名:

import { Link } from "react-router-dom";
import { useSelector } from "react-redux";

function Nav(props) {
  const user = useSelector((state) => state.user.value);
  return (
    <nav className="navbar navbar-expand navbar-light fixed-top">
      <ul className="nav">
        <li className="nav-item">
          <Link to={"/"} className="nav-link active" aria-current="page">
            Home
          </Link>
        </li>
        <li className="nav-item">
          <Link to={"/register"} className="nav-link">
            Register
          </Link>
        </li>
        <li className="nav-item">
          <Link to={"/login"} className="nav-link">
            Login
          </Link>
        </li>
        <li className="nav-item">
          <Link
            to={"/admin"}
            className="nav-link"
          >
            Admin
          </Link>
        </li>
      </ul>
      <ul className="username">
        <li>Welcome {user.name}</li>
      </ul>
    </nav>
  );
}

export default Nav;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 15:24:03