Redux Saga重定向后浏览器URL更新但组件未渲染,求解决方法
解决Redux Saga跳转后组件不渲染的问题
嘿,我一眼就看出问题所在了——你创建了两个完全独立的history实例!
路由组件里你初始化了一个history并传给<Router>,但在saga文件里又重新createHistory()了一次。这就相当于两个完全不互通的历史记录对象:saga里调用history.push只是修改了浏览器地址栏的URL,但路由系统用的是另一个实例,根本没察觉到这个跳转动作,自然不会渲染对应的组件。
下面是两种靠谱的解决方法:
方法一:共享同一个history实例(最直接)
我们把history抽成单独的模块,让路由和saga都用同一个实例:
- 创建单独的
history.js文件:
// history.js import createHistory from 'history/createBrowserHistory'; export const history = createHistory();
- 在路由组件里导入这个共享的实例:
import { history } from './history'; // ... render() { return( <Router history={history}> <PrivateRoute exact path="/dashboard" component={Dashboard}/> ... </Router> ) }
- 在saga里也导入同一个实例,去掉重复创建的代码:
import { history } from './history'; function* updateUserDetails(action) { try { const response = yield call(userServices.updateUserDetails, action.payload) if(response.data && response.data.status === 'success') { // 直接调用共享的history.push,不用再封装redirectToPage函数 yield call(history.push, '/dashboard'); } else { yield put ({ type: actionTypes.UPDATE_USER_FAILURE}); } } catch (error) { // 一定要加catch块!不然请求出错会导致saga崩溃 yield put ({ type: actionTypes.UPDATE_USER_FAILURE, payload: error.message }); } }
方法二:使用connected-react-router(进阶方案)
如果你的项目里已经用了Redux,可以用connected-react-router来同步路由状态到Redux,这样saga里可以通过dispatch action来跳转:
- 安装依赖:
npm install connected-react-router
- 配置store时集成路由 reducer:
import { createBrowserHistory } from 'history'; import { combineReducers, createStore, applyMiddleware } from 'redux'; import { connectRouter, routerMiddleware } from 'connected-react-router'; import createSagaMiddleware from 'redux-saga'; import rootSaga from './sagas'; export const history = createBrowserHistory(); const rootReducer = combineReducers({ router: connectRouter(history), // 你的其他reducer }); const sagaMiddleware = createSagaMiddleware(); const store = createStore( rootReducer, applyMiddleware( routerMiddleware(history), sagaMiddleware ) ); sagaMiddleware.run(rootSaga); export default store;
- 在saga里通过dispatch
pushaction来跳转:
import { push } from 'connected-react-router'; function* updateUserDetails(action) { try { const response = yield call(userServices.updateUserDetails, action.payload) if(response.data && response.data.status === 'success') { yield put(push('/dashboard')); } else { yield put ({ type: actionTypes.UPDATE_USER_FAILURE}); } } catch (error) { yield put ({ type: actionTypes.UPDATE_USER_FAILURE, payload: error.message }); } }
两种方法都能解决你的问题,方法一更简单直接,适合当前场景;方法二更适合复杂的路由状态管理需求。
内容的提问来源于stack exchange,提问作者prajeesh
相关产品推荐
相关产品推荐

