Reputation: 6415
Updating this question to use connected-react-router
instead of react-router-redux
since it is not compatible with react-router
v4.
I can't seem to get my routing working when dispatching an action. I suspect it's because I'm using sagas which aren't being configured properly.
I have a saga:
import { call } from 'redux-saga/effects'
import { push } from 'connected-react-router'
//...
yield call(push, '/dashboard')
The push function doesn't redirect the browser to the specified path despite the redux logs in webdev tools showing that the action was successfully dispatched.
The top level index.js file looks like:
import createSagaMiddleware from 'redux-saga'
import rootSaga from './redux/sagas'
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import logger from 'redux-logger'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
import rootReducer from './redux/modules'
import { applyMiddleware, compose, createStore } from 'redux'
import { createBrowserHistory } from 'history'
import { routerMiddleware, connectRouter } from 'connected-react-router'
const history = createBrowserHistory()
const sagaMiddleware = createSagaMiddleware()
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
connectRouter(history)(rootReducer),
composeEnhancer(
applyMiddleware(
sagaMiddleware,
routerMiddleware(history),
logger
)
)
)
sagaMiddleware.run(rootSaga)
const render = () => {
ReactDOM.render(
<Provider store={store}>
<App history={history} />
</Provider>,
document.getElementById('root')
)
}
render()
registerServiceWorker()
The App.js file containing the root component has:
import { ConnectedRouter } from 'connected-react-router'
import { Route, Switch, Redirect } from 'react-router-dom'
const App = ({ history }) => {
return (
<ConnectedRouter history={history}>
<Switch>
{ routes }
</Switch>
</ConnectedRouter>
)
}
export default App
What's missing from this setup to make it work?
Dependency versions:
"react-redux": "^5.0.7",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"connected-react-router": "^4.3.0"
Upvotes: 3
Views: 1830
Reputation: 3393
What seems to work for me is to use withRoter
(dont know if it is correct way or not):
export default withRouter(compose(withConnect)(App)); //wrapped in withRouter
Or
export default compose(
withRouter,
withConnect,
)(App);
And in redux-saga:
yield put(push('/newpage'));
I use react-boilerplate, https://github.com/react-boilerplate/react-boilerplate.
I don't know if it is correct or not but this way the route changes in url and I get to the new route. If i don't use withRouter
the route changes in url and nothing more happens...
I found solution here https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/withRouter.md
Would like to have someone opinion on that. Folks at https://github.com/react-boilerplate/react-boilerplate maybe?
Upvotes: 0
Reputation: 1554
Sagas are implemented as Generator functions that yield objects to the redux-saga middleware
So your Saga should export a Generator function:
import { call } from 'redux-saga/effects'
import { push } from 'connected-react-router'
//...
export function* rootSaga() {
return yield call(push, '/dashboard')
}
And rootSaga
should be registered with the sagaMiddleware
:
import { rootSaga } from './redux/sagas';
...
sagaMiddleware.run(rootSaga)
...
Reference: https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html
Upvotes: 0
Reputation: 5061
Unlike history
's push
method (which is an impure function), connected-react-router
's push
is an action creator and its result (action) must be dispatched to trigger a navigation.
To do so in redux-saga
you have to use put
, not call
.
call
creates a call effect.
When yielded, it simply executes given function with given arguments and returns a result. It is a good fit for (but not limited by) impure function calls (e.g. network request), by decoupling us from a direct execution of a function.
put
creates a dispatch effect.
When yielded, it dispatches passed in action object. Thus, decoupling your code only from a direct call of dispatch
, not action creator (which should be pure by design).
So, in your case, the solution would look like:
yield put(push('/dashboard'))
P.S: the same applies to react-router-redux
's push
Upvotes: 3
Reputation: 22304
you need to wire up the router's middleware, e.g.:
import { browserHistory } from 'react-router'
import { routerMiddleware } from 'react-router-redux'
const sagaMw = createSagaMiddleware()
const routerMw = routerMiddleware(browserHistory)
const middleware = applyMiddleware(sagaMw, routerMw, logger)
Upvotes: 2