如何在Redux-Saga中使用history推送路由?React Router v4场景
我经常碰到这种场景,其实有两种靠谱的解决方案,你可以根据自己的需求来选:
方法一:创建独立的History实例(最简单直接)
因为BrowserRouter会在内部自动创建history对象,导致外部无法访问,所以我们可以手动创建一个history实例,再传递给路由组件,这样Saga里就能直接导入使用了:
- 首先安装
history包:npm install history # 或者用yarn yarn add history - 在项目里新建一个
history.js文件,导出创建好的BrowserHistory实例:// src/history.js import { createBrowserHistory } from 'history'; export default createBrowserHistory(); - 把原来的
BrowserRouter替换成react-router-dom里的Router组件,传入我们创建的history:// src/App.js 或者你的入口路由文件 import { Router, Route, Switch } from 'react-router-dom'; import history from './history'; function App() { return ( <Router history={history}> <Switch> {/* 你的路由配置,比如: */} <Route path="/" exact component={Home} /> <Route path="/about" component={About} /> </Switch> </Router> ); } - 现在在你的Saga里,直接导入history就能调用
push做重定向了:// src/sagas/yourSaga.js import history from '../history'; import { call } from 'redux-saga/effects'; function* handleSomeAction() { // 先处理你的业务逻辑,比如API请求、状态更新 // ... // 执行路由跳转 yield call(history.push, '/target-page'); // 也可以直接写history.push('/target-page'),但用call更符合Saga的副作用处理规范,方便后续测试 }
方法二:通过Connected-React-Router集成Redux与路由(适合需要路由状态同步的场景)
如果你的项目需要把路由状态同步到Redux中(比如在Reducer里响应路由变化、或者追踪路由历史),可以用connected-react-router这个库,它能让你通过Redux action来触发路由跳转:
- 先安装依赖:
npm install connected-react-router history # 或者yarn yarn add connected-react-router history - 同样先创建
history.js文件(和方法一一样):// src/history.js import { createBrowserHistory } from 'history'; export default createBrowserHistory(); - 配置Redux Store的时候,集成
connected-react-router的reducer和中间件:// src/store/configureStore.js import { createStore, applyMiddleware, combineReducers } from 'redux'; import { connectRouter, routerMiddleware } from 'connected-react-router'; import createSagaMiddleware from 'redux-saga'; import history from '../history'; // 导入你的其他reducers和sagas import rootReducer from './reducers'; import rootSaga from './sagas'; const sagaMiddleware = createSagaMiddleware(); // 合并路由reducer到你的根reducer const rootReducerWithRouter = connectRouter(history)(combineReducers({ ...rootReducer, // 这里放你的其他reducers })); const store = createStore( rootReducerWithRouter, applyMiddleware( routerMiddleware(history), // 加入路由中间件 sagaMiddleware ) ); sagaMiddleware.run(rootSaga); export default store; - 在入口文件里用
ConnectedRouter替换原来的BrowserRouter:// src/index.js import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { ConnectedRouter } from 'connected-react-router'; import store from './store/configureStore'; import history from './history'; import App from './App'; ReactDOM.render( <Provider store={store}> <ConnectedRouter history={history}> <App /> </ConnectedRouter> </Provider>, document.getElementById('root') ); - 现在在Saga里,你可以通过dispatch
pushaction来实现路由跳转:// src/sagas/yourSaga.js import { put } from 'redux-saga/effects'; import { push } from 'connected-react-router'; function* handleSomeAction() { // 处理业务逻辑... // 通过Redux action触发跳转 yield put(push('/target-page')); }
两种方法的选择建议
- 如果只是单纯需要在Saga里做路由跳转,方法一足够简单,不需要引入额外的Redux集成逻辑;
- 如果你的项目需要在Redux中管理路由状态(比如在Reducer里根据路由变化更新状态、或者需要监听路由动作),那么方法二更适合。
内容的提问来源于stack exchange,提问作者erich
相关产品推荐
相关产品推荐

