升级React Router v6后,如何在Redux Saga中使用useNavigate导航?
解决Redux Saga中React Router v6导航问题的方案
因为你已经移除了connected-react-router,又不想每次派发Action都传useNavigate,下面几个实用方案可以适配你现有代码的情况:
方案1:将navigate实例存入Redux Store
在根组件中获取useNavigate实例并存入Redux,之后在Saga里通过select取出使用:
- 创建管理导航的slice:
// features/navigate/navigateSlice.ts import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { NavigateFunction } from 'react-router-dom'; interface NavigateState { navigate: NavigateFunction | null; } const initialState: NavigateState = { navigate: null, }; export const navigateSlice = createSlice({ name: 'navigate', initialState, reducers: { setNavigate: (state, action: PayloadAction<NavigateFunction>) => { state.navigate = action.payload; }, }, }); export const { setNavigate } = navigateSlice.actions; export const selectNavigate = (state: RootState) => state.navigate.navigate;
- 在根组件注入navigate实例:
// App.tsx import { useNavigate } from 'react-router-dom'; import { useDispatch } from 'react-redux'; import { setNavigate } from './features/navigate/navigateSlice'; import { useEffect } from 'react'; function App() { const navigate = useNavigate(); const dispatch = useDispatch(); useEffect(() => { dispatch(setNavigate(navigate)); }, [navigate, dispatch]); return ( {/* 你的应用内容 */} ); }
- 在Saga中取出使用:
function* watchStatus( action: ActionType<typeof startActions.changeStatus> ): SagaIterator { if (action.payload.status === "END_CREATE") { const data: ReturnType<typeof getDataRequest> = yield select( getDataRequest ); } else if (action.payload.status === "END_VIEW") { const navigate = yield select(selectNavigate); navigate('/target-path'); } }
方案2:全局导航服务(单例模式)
创建独立的导航服务文件,用单例存储navigate实例,Saga中直接导入调用:
- 编写导航服务:
// services/navigateService.ts import { NavigateFunction } from 'react-router-dom'; let navigateInstance: NavigateFunction | null = null; export const navigateService = { setNavigate: (navigate: NavigateFunction) => { navigateInstance = navigate; }, navigate: (to: string) => { navigateInstance?.(to); }, };
- 在根组件初始化服务:
// App.tsx import { useNavigate } from 'react-router-dom'; import { navigateService } from './services/navigateService'; import { useEffect } from 'react'; function App() { const navigate = useNavigate(); useEffect(() => { navigateService.setNavigate(navigate); }, [navigate]); return ( {/* 你的应用内容 */} ); }
- 在Saga中直接调用:
import { navigateService } from '../services/navigateService'; function* watchStatus( action: ActionType<typeof startActions.changeStatus> ): SagaIterator { if (action.payload.status === "END_CREATE") { const data: ReturnType<typeof getDataRequest> = yield select( getDataRequest ); } else if (action.payload.status === "END_VIEW") { navigateService.navigate('/target-path'); } }
方案3:Action触发+组件监听导航
让Saga派发导航Action,在组件中监听并执行导航,更符合Redux单向数据流:
- 定义导航Action和slice:
// features/navigate/navigateSlice.ts import { createSlice, PayloadAction } from '@reduxjs/toolkit'; interface NavigateState { targetPath: string | null; } const initialState: NavigateState = { targetPath: null, }; export const navigateSlice = createSlice({ name: 'navigate', initialState, reducers: { navigateTo: (state, action: PayloadAction<string>) => { state.targetPath = action.payload; }, resetTargetPath: (state) => { state.targetPath = null; }, }, }); export const { navigateTo, resetTargetPath } = navigateSlice.actions; export const selectTargetPath = (state: RootState) => state.navigate.targetPath;
- 在Saga中派发导航Action:
import { navigateTo } from '../features/navigate/navigateSlice'; function* watchStatus( action: ActionType<typeof startActions.changeStatus> ): SagaIterator { if (action.payload.status === "END_CREATE") { const data: ReturnType<typeof getDataRequest> = yield select( getDataRequest ); } else if (action.payload.status === "END_VIEW") { yield put(navigateTo('/target-path')); } }
- 在根组件监听并执行导航:
// App.tsx import { useNavigate } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; import { selectTargetPath, resetTargetPath } from './features/navigate/navigateSlice'; import { useEffect } from 'react'; function App() { const navigate = useNavigate(); const targetPath = useSelector(selectTargetPath); const dispatch = useDispatch(); useEffect(() => { if (targetPath) { navigate(targetPath); dispatch(resetTargetPath()); } }, [targetPath, navigate, dispatch]); return ( {/* 你的应用内容 */} ); }
内容的提问来源于stack exchange,提问作者pitchdiesel
相关产品推荐
相关产品推荐

