Skip to content

Commit

Permalink
Migration from react-router-redux to connected-react-router (#2375)
Browse files Browse the repository at this point in the history
* Migrated from react-router-redux to connected-react-router

* Readability and protection for createReducer function

* Switch to default param in createReducer

* Documentation update for switch to connected-react-router
  • Loading branch information
julienben committed Oct 11, 2018
1 parent ff0efa1 commit 0fd55a4
Show file tree
Hide file tree
Showing 15 changed files with 88 additions and 156 deletions.
8 changes: 4 additions & 4 deletions app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import '@babel/polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import Immutable from 'immutable';
import { ConnectedRouter } from 'connected-react-router/immutable';
import FontFaceObserver from 'fontfaceobserver';
import createHistory from 'history/createBrowserHistory';
import history from 'utils/history';
import 'sanitize.css/sanitize.css';

// Import root app
Expand Down Expand Up @@ -45,8 +46,7 @@ openSansObserver.load().then(() => {
});

// Create redux store with history
const initialState = {};
const history = createHistory();
const initialState = Immutable.Map();
const store = configureStore(initialState, history);
const MOUNT_NODE = document.getElementById('app');

Expand Down
8 changes: 2 additions & 6 deletions app/configureStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { createStore, applyMiddleware, compose } from 'redux';
import { fromJS } from 'immutable';
import { routerMiddleware } from 'react-router-redux';
import { routerMiddleware } from 'connected-react-router/immutable';
import createSagaMiddleware from 'redux-saga';
import createReducer from './reducers';

Expand All @@ -24,11 +24,7 @@ export default function configureStore(initialState = {}, history) {
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// TODO: Try to remove when `react-router-redux` is out of beta, LOCATION_CHANGE should not be fired more than once after hot reloading
// Prevent recomputing reducers for `replaceReducer`
shouldHotReload: false,
})
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;
/* eslint-enable */

Expand Down
43 changes: 9 additions & 34 deletions app/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,24 @@
* Combine all reducers in this file and export the combined reducers.
*/

import { fromJS } from 'immutable';
import { combineReducers } from 'redux-immutable';
import { LOCATION_CHANGE } from 'react-router-redux';
import { connectRouter } from 'connected-react-router/immutable';

import history from 'utils/history';
import globalReducer from 'containers/App/reducer';
import languageProviderReducer from 'containers/LanguageProvider/reducer';

/*
* routeReducer
*
* The reducer merges route location changes into our immutable state.
* The change is necessitated by moving to react-router-redux@5
*
*/

// Initial routing state
const routeInitialState = fromJS({
location: null,
});

/**
* Merge route into the global application state
*/
export function routeReducer(state = routeInitialState, action) {
switch (action.type) {
/* istanbul ignore next */
case LOCATION_CHANGE:
return state.merge({
location: action.payload,
});
default:
return state;
}
}

/**
* Creates the main reducer with the dynamically injected ones
* Merges the main reducer with the router state and dynamically injected reducers
*/
export default function createReducer(injectedReducers) {
return combineReducers({
route: routeReducer,
export default function createReducer(injectedReducers = {}) {
const rootReducer = combineReducers({
global: globalReducer,
language: languageProviderReducer,
...injectedReducers,
});

// Wrap the root reducer and return a new root reducer with router state
const mergeWithRouterState = connectRouter(history);
return mergeWithRouterState(rootReducer);
}
24 changes: 0 additions & 24 deletions app/tests/reducers.test.js

This file was deleted.

3 changes: 3 additions & 0 deletions app/utils/history.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import createHistory from 'history/createBrowserHistory';
const history = createHistory();
export default history;
4 changes: 2 additions & 2 deletions docs/general/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ visible page for the best performance.
## Industry-standard routing

It's natural to want to add pages (e.g. `/about`) to your application, and
routing makes this possible. Thanks to [react-router] with [react-router-redux],
routing makes this possible. Thanks to [react-router] with [connected-react-router],
that's as easy as pie and the url is auto-synced to your application state!

[react-router]: https://github.com/reactjs/react-router
[react-router-redux]: https://github.com/reactjs/react-router-redux
[connected-react-router]: https://github.com/supasate/connected-react-router

## Static code analysis

Expand Down
2 changes: 1 addition & 1 deletion docs/js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ via [`reselect`](reselect.md).

For managing asynchronous flows (e.g. logging in) we use [`redux-saga`](redux-saga.md).

For routing, we use [`react-router` in combination with `react-router-redux`](routing.md).
For routing, we use [`react-router` in combination with `connected-react-router`](routing.md).

We include a generator for components, containers, sagas, routes and selectors.
Run `npm run generate` to choose from the available generators, and automatically
Expand Down
23 changes: 17 additions & 6 deletions docs/js/routing.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Routing via `react-router` and `react-router-redux`
# Routing via `react-router` and `connected-react-router`

`react-router` is the de-facto standard routing solution for react applications.
The thing is that with redux and a single state tree, the URL is part of that
state. `react-router-redux` takes care of synchronizing the location of our
state. `connected-react-router` takes care of synchronizing the location of our
application with the application state.

(See the [`react-router-redux` documentation](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux)
(See the [`connected-react-router` FAQ](https://github.com/supasate/connected-react-router/blob/master/FAQ.md)
for more information)

## Usage
Expand All @@ -20,12 +20,23 @@ Top level routes are located in `App.js`.

If you want your route component (or any component for that matter) to be loaded asynchronously, use container or component generator with 'Do you want an async loader?' option activated.

To go to a new page use the `push` function by `react-router-redux`:
To go to a new page use the `push` function by `connected-react-router`:

```JS
import { push } from 'react-router-redux';
import { push } from 'connected-react-router/immutable';

dispatch(push('/some/page'));
dispatch(push('/path/to/somewhere'));
```

You can do the same thing in a saga:

```JS
import { push } from 'connected-react-router/immutable'
import { put } from 'redux-saga/effects'

export function* mySaga() {
yield put(push('/home'))
}
```

## Child Routes
Expand Down
8 changes: 4 additions & 4 deletions internals/templates/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import '@babel/polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
import Immutable from 'immutable';
import { ConnectedRouter } from 'connected-react-router/immutable';
import history from 'utils/history';
import 'sanitize.css/sanitize.css';

// Import root app
Expand All @@ -37,8 +38,7 @@ import { translationMessages } from './i18n';
import './global-styles';

// Create redux store with history
const initialState = {};
const history = createHistory();
const initialState = Immutable.Map();
const store = configureStore(initialState, history);
const MOUNT_NODE = document.getElementById('app');

Expand Down
8 changes: 2 additions & 6 deletions internals/templates/configureStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { createStore, applyMiddleware, compose } from 'redux';
import { fromJS } from 'immutable';
import { routerMiddleware } from 'react-router-redux';
import { routerMiddleware } from 'connected-react-router/immutable';
import createSagaMiddleware from 'redux-saga';
import createReducer from './reducers';

Expand All @@ -24,11 +24,7 @@ export default function configureStore(initialState = {}, history) {
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// TODO Try to remove when `react-router-redux` is out of beta, LOCATION_CHANGE should not be fired more than once after hot reloading
// Prevent recomputing reducers for `replaceReducer`
shouldHotReload: false,
})
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose;
/* eslint-enable */

Expand Down
43 changes: 9 additions & 34 deletions internals/templates/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,21 @@
*/

import { combineReducers } from 'redux-immutable';
import { fromJS } from 'immutable';
import { LOCATION_CHANGE } from 'react-router-redux';
import { connectRouter } from 'connected-react-router/immutable';

import history from 'utils/history';
import languageProviderReducer from 'containers/LanguageProvider/reducer';

/*
* routeReducer
*
* The reducer merges route location changes into our immutable state.
* The change is necessitated by moving to react-router-redux@4
*
*/

// Initial routing state
const routeInitialState = fromJS({
location: null,
});

/**
* Merge route into the global application state
*/
export function routeReducer(state = routeInitialState, action) {
switch (action.type) {
/* istanbul ignore next */
case LOCATION_CHANGE:
return state.merge({
location: action.payload,
});
default:
return state;
}
}

/**
* Creates the main reducer with the dynamically injected ones
* Merges the main reducer with the router state and dynamically injected reducers
*/
export default function createReducer(injectedReducers) {
return combineReducers({
route: routeReducer,
export default function createReducer(injectedReducers = {}) {
const rootReducer = combineReducers({
language: languageProviderReducer,
...injectedReducers,
});

// Wrap the root reducer and return a new root reducer with router state
const mergeWithRouterState = connectRouter(history);
return mergeWithRouterState(rootReducer);
}
24 changes: 0 additions & 24 deletions internals/templates/tests/reducers.test.js

This file was deleted.

3 changes: 3 additions & 0 deletions internals/templates/utils/history.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import createHistory from 'history/createBrowserHistory';
const history = createHistory();
export default history;
41 changes: 31 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0fd55a4

Please sign in to comment.