Search code examples
reactjsreact-routerredux-saga

Redirect to Route from Saga using React Router v6


I'm using redux saga & react router v6 and I want to redirect to a route from one of my sagas, is there a way to do it ?


Solution

  • There are multiple options


    1 - Sending the navigate method as part of dispatched redux action

    // component
    const navigate = useNavigate()
    dispatch({type: FOO, navigate})
    
    // saga
    yield takeEvery(FOO, function*(action) {
      action.navigate('/foo')
    })
    

    Pros:

    • You are using the navigate method which is recommended by the react-router team
    • The API is unlikely to change

    Cons

    • You have access to the navigate method only in specific sagas that received such action
    • You have unserializable data in your actions

    2 - Another option is to store the navigate method in some way. E.g. you can create a dummy react component that will get the navigate method through useNavigate hook and then store it in some "global" variable. See this SO answer for a possible solution: https://stackoverflow.com/a/70002872/2347716

    This deals with the the cons from previous solution, but there are still some issues:

    • You need your React tree to render at least once before you have access to the navigate method
    • You are adding non-view complexity to your view layer by introducing the dummy component

    3 - There is another solution, similar to what we had with react-router 5 that deals with the issues in the previous solution. It is to use the history object. It is not documented since its unstable, but there is a HistoryRouter implementation as part of the react-router-dom package. See https://github.com/remix-run/react-router/releases/tag/v6.1.1

    import {unstable_HistoryRouter as HistoryRouter} from 'react-router-dom'
    import { createBrowserHistory } from "history";
    const history = createBrowserHistory()
    
    // saga setup
    sagaMiddleware.runSaga(rootSaga, history);
    
    // react
    <HistoryRouter history={history} />
    

    The issue with this solution is that it is unstable because it might have some issues with some of React 18 features. Personally I prefer it since it solves everything else and we can deal with React 18 issues once its actually released and we know what they are.