Redux Observable Epic内路由跳转失败问题求助
解决Redux Observable Epic中登录成功后路由跳转无效的问题
嘿,我看了你遇到的问题,刚接触Redux Observable确实容易在路由跳转这里踩坑,我帮你分析下问题所在,然后一步步解决:
核心问题分析
你现在的问题主要出在两个地方:
- 双重History实例冲突:你在
App.ts里用了BrowserRouter,它会自己创建一个内部的history对象,但你的Redux store用的是自定义的history实例,这俩完全独立。所以当你通过Redux发送pushaction时,store里的路由状态变了,但React Router组件根本感知不到,自然页面不会跳转。 - 错误的action生成方式:直接调用
history.push('/')会修改地址栏,但它返回的是undefined,你用mapTo(history.push('/'))相当于让Epic输出了一个undefined的action,而Redux要求每个action必须有type属性,这就导致了那个"Cannot read property 'type' of undefined"的错误。
一步步解决
1. 用ConnectedRouter替换BrowserRouter
connected-react-router提供的ConnectedRouter会和你的Redux store共享同一个history实例,这样路由状态才能同步到组件。修改你的App.ts:
// 导入ConnectedRouter和你的自定义history import { ConnectedRouter } from 'connected-react-router'; import { history } from './history'; export default function App() { const { configureStore } = require('./store/configureStore'); const store = configureStore(); return ( <Provider store={store}> {/* 把BrowserRouter换成ConnectedRouter,传入你的history */} <ConnectedRouter history={history} basename={basename}> <Routes /> </ConnectedRouter> </Provider> ); }
2. 在Epic中正确使用push action creator
导入connected-react-router的push action creator,用它来生成跳转action,而不是直接调用history.push。修改你的fetchProfileSuccess Epic:
// 先导入push import { push } from 'connected-react-router'; const fetchProfileSuccess: Epic = action$ => action$.pipe( ofType(FETCH_PROFILE_SUCCESS), // 这里发送push action,交给routerMiddleware处理 mapTo(push('/')) );
3. 确认中间件顺序正确
在configureStore.ts里,routerMiddleware要放在epicMiddleware前面(因为Redux的中间件是从右到左执行的,routerMiddleware需要先处理路由action):
export function configureStore() { const epicMiddleware = createEpicMiddleware<AllActions, AllActions, AppState>(); const store = createStore( rootReducer(history), composeWithDevTools( // routerMiddleware在前,epicMiddleware在后 applyMiddleware(routerMiddleware(history), epicMiddleware) ) ); epicMiddleware.run(rootEpic); return store; }
额外检查:确认rootReducer集成了routerReducer
确保你的根reducer已经正确合并了connected-react-router的路由reducer:
// rootReducer.ts import { combineReducers } from 'redux'; import { connectRouter } from 'connected-react-router'; import { history } from './history'; import authReducer from './auth'; // 把router reducer添加到根reducer里 export const rootReducer = (history: any) => combineReducers({ router: connectRouter(history), auth: authReducer, // 其他你的reducers... });
这样修改后,当FETCH_PROFILE_SUCCESS action触发时,Epic会发送push('/') action,routerMiddleware会处理这个action更新store里的路由状态,ConnectedRouter会监听store变化,自动把页面跳转到首页,URL和页面就同步啦!
内容的提问来源于stack exchange,提问作者Aron
相关产品推荐
相关产品推荐

