Breaking change in v5.0.0! Please read How to migrate from v4 to v5/v6.
v6.0.0 requires React v16.4.0 and React Redux v6.0 / v7.0.
A Redux binding for React Router v4 and v5
β¨ Synchronize router state with redux store through uni-directional flow (i.e. history -> store -> router -> components).
π Supports React Router v4 and v5.
βοΈ Supports functional component hot reloading while preserving state (with react-hot-reload).
π Dispatching of history methods (push
, replace
, go
, goBack
, goForward
) works for both redux-thunk and redux-saga.
β Nested children can access routing state such as the current location directly with react-redux
's connect
.
π Supports time traveling in Redux DevTools.
π Supports Immutable.js
πͺ Supports TypeScript
Connected React Router requires React 16.4 and React Redux 6.0 or later.
npm install --save connected-react-router
Or
yarn add connected-react-router
In your root reducer file,
- Create a function that takes
history
as an argument and returns a root reducer. - Add
router
reducer into root reducer by passinghistory
toconnectRouter
. - Note: The key MUST be
router
.
// reducers.js import { combineReducers } from 'redux' import { connectRouter } from 'connected-react-router' const createRootReducer = (history) => combineReducers({ router: connectRouter(history), ... // rest of your reducers }) export default createRootReducer
When creating a Redux store,
- Create a
history
object. - Provide the created
history
to the root reducer creator. - Use
routerMiddleware(history)
if you want to dispatch history actions (e.g. to change URL withpush('/path/to/somewhere')
).
// configureStore.js ... import { createBrowserHistory } from 'history' import { applyMiddleware, compose, createStore } from 'redux' import { routerMiddleware } from 'connected-react-router' import createRootReducer from './reducers' ... export const history = createBrowserHistory() export default function configureStore(preloadedState) { const store = createStore( createRootReducer(history), // root reducer with router state preloadedState, compose( applyMiddleware( routerMiddleware(history), // for dispatching history actions // ... other middlewares ... ), ), ) return store }
- Wrap your react-router v4/v5 routing with
ConnectedRouter
and pass thehistory
object as a prop. Remember to delete any usage ofBrowserRouter
orNativeRouter
as leaving this in will cause problems synchronising the state. - Place
ConnectedRouter
as a child ofreact-redux
'sProvider
. - N.B. If doing server-side rendering, you should still use the
StaticRouter
fromreact-router
on the server.
// index.js ... import { Provider } from 'react-redux' import { Route, Switch } from 'react-router' // react-router v4/v5 import { ConnectedRouter } from 'connected-react-router' import configureStore, { history } from './configureStore' ... const store = configureStore(/* provide initial state if any */) ReactDOM.render( <Provider store={store}> <ConnectedRouter history={history}> { /* place ConnectedRouter under Provider */ } <> { /* your usual react-router v4/v5 routing */ } <Switch> <Route exact path="/" render={() => (<div>Match</div>)} /> <Route render={() => (<div>Miss</div>)} /> </Switch> </> </ConnectedRouter> </Provider>, document.getElementById('react-root') )
Note: the history
object provided to router
reducer, routerMiddleware
, and ConnectedRouter
component must be the same history
object.
Now, it's ready to work!
See the examples folder
- How to navigate with Redux action
- How to get the current browser location (URL)
- How to set Router props e.g. basename, initialEntries, etc.
- How to hot reload functional components
- How to hot reload reducers
- How to support Immutable.js
- How to implement server-side rendering (sample codebase)
- How to migrate from v4 to v5
- How to use connected-react-router with react native
- How to use your own context with react-redux
npm run build
Generated files will be in the lib
folder.
When testing the example apps with npm link
or yarn link
, you should explicitly provide the same Context
to both Provider
and ConnectedRouter
to make sure that the ConnectedRouter
doesn't pick up a different ReactReduxContext
from a different node_modules
folder.
In index.js
.
... import { Provider, ReactReduxContext } from 'react-redux' ... <Provider store={store} context={ReactReduxContext}> <App history={history} context={ReactReduxContext} /> </Provider> ...
In App.js
,
... const App = ({ history, context }) => { return ( <ConnectedRouter history={history} context={context}> { routes } </ConnectedRouter> ) } ...
See Contributors and Acknowledge.