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

React+Redux登出报错Actions must be plain objects及跳转异常排查

问题根因

你遇到的跳转后回退、action类型报错是三个问题叠加导致的:

  • 退出按钮设置了to="#"属性,点击时会触发默认锚点跳转,触发页面重载,中断会话清除逻辑
  • sessionService.deleteSession()和sessionService.deleteUser()是异步Promise操作,原代码没有等待操作执行完成就直接路由跳转,此时本地会话信息还未被清除,页面刷新后会话被自动恢复,就会跳转回仪表盘
  • 组件中同时混用connect高阶组件绑定action和useDispatch手动调度,写法冗余,修改代码时很容易出现action返回值不符合thunk要求的问题,触发Actions must be plain objects报错
修复步骤

1. 修正logoutUser action,等待异步会话清除完成

修改userAction.js中的logoutUser方法,等待会话和用户信息彻底删除后再执行路由跳转:

export const logoutUser = (navigate) => {
  return async (dispatch) => {
    // 等待异步清除操作执行完毕
    await sessionService.deleteSession();
    await sessionService.deleteUser();
    navigate('/');
  }
}

注:你原代码中的loginUser、signupUser没有同类报错是因为内部用了.then链式调用保证执行顺序,但登出逻辑缺少异步等待,直接跳转就会出现状态残留。

2. 简化Dashboard组件写法,阻止按钮默认跳转行为

去掉冗余的connect绑定(和useDispatch二选一即可,不需要同时使用),点击登出按钮时先阻止默认的锚点跳转行为,再触发登出逻辑:

// 移除connect相关导入,统一用react-redux hook写法
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { logoutUser } from '../../auth/actions/userActions';

const Dashboard = () => {
  const navigate = useNavigate();
  const dispatch = useDispatch();

  const handleLogout = (e) => {
    // 阻止to="#"带来的默认锚点跳转/页面刷新
    e.preventDefault();
    dispatch(logoutUser(navigate));
  }

  return (
    <div>
      <div>
        <Avatar image={Logo} />
      </div>
      <StyledFormArea bg={colors.dark2} style={{ marginLeft: '-400px' }}>
        <StyledTitle size={65}>Welcome to Dashboard </StyledTitle>
        <StyledSubTitle size={27}>Feel free to post new jobs</StyledSubTitle>
        <Formik
          initialValues={{
            title: '',
            description: ''
          }}
        >
          <Form>
            <TextInput
              name="title"
              type="text"
              label="Title :"
              placeholder="Job Title"
            />
            <TextInput
              name="description"
              type="text"
              label="Description :"
              placeholder="Job description"
            />
          </Form>
        </Formik>
        <ButtonGroup>
          <StyledButton to="#">Post Job</StyledButton>
          <StyledButton
            bg={colors.red}
            to="#"
            onClick={handleLogout}
          >
            Logout
          </StyledButton>
        </ButtonGroup>
      </StyledFormArea>
    </div>
  );
};

// 移除原有的connect包裹,直接导出组件
export default Dashboard;

如果你更习惯用connect写法,也可以保留connect,去掉组件内的useDispatch调用,只要在点击事件里加e.preventDefault()即可,两种写法选一种不要混用。

3. 验证store配置

你的store配置已经正确加载了redux-thunk中间件,不需要额外修改,只要保证sessionService.initSessionService(store)在store创建完成后调用即可。

验证逻辑

修改后点击登出按钮:

  1. 首先阻止默认页面跳转,不会触发意外刷新
  2. thunk action执行,等待本地存储的会话、用户信息彻底清除
  3. 清除完成后再跳转到首页,此时redux-react-session检测不到有效会话,不会再自动跳回仪表盘

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:27:16