如何在Redux saga中借助react-router实现无页面刷新跳转?
解决方案
以下是两种可实现无刷新跳转的常用方案,你可以根据项目实际情况选择:
方案1:在saga中直接调用共享history实例,适配现有代码结构
该方案改动量最小,不需要调整原有逻辑分层:
- 首先创建全局共享的history实例,新建
src/utils/history.js文件:
import { createBrowserHistory } from 'history'; export default createBrowserHistory();
- 调整项目根路由的包裹组件,react-router v6版本写法如下:
// 根组件App.js import { unstable_HistoryRouter as HistoryRouter } from 'react-router-dom'; import history from './utils/history'; function App() { return ( <HistoryRouter history={history}> {/* 原有路由配置保持不变 */} </HistoryRouter> ); }
如果是react-router v5版本,直接把unstable_HistoryRouter替换为Router即可。
- 修改saga代码,导入history实例替换原有window.location逻辑:
import history from 'path/to/utils/history'; // 替换为你实际的文件路径 function* fetchData(){ try{ yield call(editgetUser) yield put(userEditSuccess); history.push("/user/home") } catch(e){ // 原有代码存在多余yield的笔误,已删除 yield put(userEditFailure); history.push("/user/login") } } function* watchFetchData(){ yield takeEvery(EDIT, fetchData); }
方案2:跳转逻辑移到组件层,职责拆分更清晰
该方案符合单向数据流规范,saga只负责处理业务逻辑,路由跳转交给组件处理,耦合度更低:
- 先简化saga代码,只保留状态更新逻辑,删除跳转相关代码:
function* fetchData(){ try{ yield call(editgetUser) yield put(userEditSuccess()); } catch(e){ yield put(userEditFailure()); } } function* watchFetchData(){ yield takeEvery(EDIT, fetchData); }
- 在触发编辑action的组件中,监听redux中的编辑状态,调用react-router的
useNavigate实现跳转:
import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useSelector } from 'react-redux'; function UserEditPage() { const navigate = useNavigate(); // 替换为你项目中实际对应的redux状态路径 const { editSuccess, editFailed } = useSelector(state => state.userModule); useEffect(() => { if (editSuccess) { navigate('/user/home'); } if (editFailed) { navigate('/user/login'); } }, [editSuccess, editFailed, navigate]) // 原有组件逻辑、触发EDIT action的代码保持不变 }
补充说明
两种方案都可以完全避免页面刷新,方案1适合快速迭代的小项目,方案2更适合需要长期维护的中大型项目,可测试性更强。
内容的提问来源于stack exchange,提问作者Ghulam Azam Khan
相关产品推荐
相关产品推荐

