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创建完成后调用即可。
验证逻辑
修改后点击登出按钮:
- 首先阻止默认页面跳转,不会触发意外刷新
- thunk action执行,等待本地存储的会话、用户信息彻底清除
- 清除完成后再跳转到首页,此时redux-react-session检测不到有效会话,不会再自动跳回仪表盘
内容的提问来源于stack exchange,提问作者Darkpsinight
相关产品推荐
相关产品推荐

