[d24f17c] | 1 | # `redux-immutable`
|
---|
| 2 |
|
---|
| 3 | [](https://travis-ci.org/gajus/redux-immutable)
|
---|
| 4 | [](https://www.npmjs.org/package/redux-immutable)
|
---|
| 5 | [](https://github.com/gajus/canonical)
|
---|
| 6 |
|
---|
| 7 | `redux-immutable` is used to create an equivalent function of Redux [`combineReducers`](http://redux.js.org/docs/api/combineReducers.html) that works with [Immutable.js](https://facebook.github.io/immutable-js/) state.
|
---|
| 8 |
|
---|
| 9 | When Redux [`createStore`](https://github.com/reactjs/redux/blob/master/docs/api/createStore.md) `reducer` is created using `redux-immutable` then `initialState` must be an instance of [`Immutable.Collection`](https://facebook.github.io/immutable-js/docs/#/Collection).
|
---|
| 10 |
|
---|
| 11 | ## Problem
|
---|
| 12 |
|
---|
| 13 | When [`createStore`](https://github.com/reactjs/redux/blob/v3.0.6/docs/api/createStore.md) is invoked with `initialState` that is an instance of `Immutable.Collection` further invocation of reducer will [produce an error](https://github.com/reactjs/redux/blob/v3.0.6/src/combineReducers.js#L31-L38):
|
---|
| 14 |
|
---|
| 15 | > The initialState argument passed to createStore has unexpected type of "Object".
|
---|
| 16 | > Expected argument to be an object with the following keys: "data"
|
---|
| 17 |
|
---|
| 18 | This is because Redux `combineReducers` [treats `state` object as a plain JavaScript object](https://github.com/reactjs/redux/blob/v3.0.6/src/combineReducers.js#L120-L129).
|
---|
| 19 |
|
---|
| 20 | `combineReducers` created using `redux-immutable` uses Immutable.js API to iterate the state.
|
---|
| 21 |
|
---|
| 22 | ## Usage
|
---|
| 23 |
|
---|
| 24 | Create a store with `initialState` set to an instance of [`Immutable.Collection`](https://facebook.github.io/immutable-js/docs/#/Collection):
|
---|
| 25 |
|
---|
| 26 | ```js
|
---|
| 27 | import {
|
---|
| 28 | combineReducers
|
---|
| 29 | } from 'redux-immutable';
|
---|
| 30 |
|
---|
| 31 | import {
|
---|
| 32 | createStore
|
---|
| 33 | } from 'redux';
|
---|
| 34 |
|
---|
| 35 | const initialState = Immutable.Map();
|
---|
| 36 | const rootReducer = combineReducers({});
|
---|
| 37 | const store = createStore(rootReducer, initialState);
|
---|
| 38 | ```
|
---|
| 39 |
|
---|
| 40 | By default, if `state` is `undefined`, `rootReducer(state, action)` is called with `state = Immutable.Map()`. A different default function can be provided as the second parameter to `combineReducers(reducers, getDefaultState)`, for example:
|
---|
| 41 |
|
---|
| 42 | ```js
|
---|
| 43 | const StateRecord = Immutable.Record({
|
---|
| 44 | foo: 'bar'
|
---|
| 45 | });
|
---|
| 46 | const rootReducer = combineReducers({foo: fooReducer}, StateRecord);
|
---|
| 47 | // rootReducer now has signature of rootReducer(state = StateRecord(), action)
|
---|
| 48 | // state now must always have 'foo' property with 'bar' as its default value
|
---|
| 49 | ```
|
---|
| 50 |
|
---|
| 51 | When using `Immutable.Record` it is possible to delegate default values to child reducers:
|
---|
| 52 |
|
---|
| 53 | ```js
|
---|
| 54 | const StateRecord = Immutable.Record({
|
---|
| 55 | foo: undefined
|
---|
| 56 | });
|
---|
| 57 | const rootReducer = combineReducers({foo: fooReducer}, StateRecord);
|
---|
| 58 | // state now must always have 'foo' property with its default value returned from fooReducer(undefined, action)
|
---|
| 59 | ```
|
---|
| 60 |
|
---|
| 61 | In general, `getDefaultState` function must return an instance of `Immutable.Record` or `Immutable.Collection` that implements `get`, `set` and `withMutations` methods. Such collections are `List`, `Map` and `OrderedMap`.
|
---|
| 62 |
|
---|
| 63 | ### Using with `react-router-redux`
|
---|
| 64 |
|
---|
| 65 | `react-router-redux` [`routeReducer`](https://github.com/reactjs/react-router-redux/tree/v4.0.2#routerreducer) does not work with Immutable.js. You need to use a custom reducer:
|
---|
| 66 |
|
---|
| 67 | ```js
|
---|
| 68 | import Immutable from 'immutable';
|
---|
| 69 | import {
|
---|
| 70 | LOCATION_CHANGE
|
---|
| 71 | } from 'react-router-redux';
|
---|
| 72 |
|
---|
| 73 | const initialState = Immutable.fromJS({
|
---|
| 74 | locationBeforeTransitions: null
|
---|
| 75 | });
|
---|
| 76 |
|
---|
| 77 | export default (state = initialState, action) => {
|
---|
| 78 | if (action.type === LOCATION_CHANGE) {
|
---|
| 79 | return state.set('locationBeforeTransitions', action.payload);
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | return state;
|
---|
| 83 | };
|
---|
| 84 | ```
|
---|
| 85 |
|
---|
| 86 | Pass a selector to access the payload state and convert it to a JavaScript object via the [`selectLocationState` option on `syncHistoryWithStore`](https://github.com/reactjs/react-router-redux/tree/v4.0.2#history--synchistorywithstorehistory-store-options):
|
---|
| 87 |
|
---|
| 88 | ```js
|
---|
| 89 | import {
|
---|
| 90 | browserHistory
|
---|
| 91 | } from 'react-router';
|
---|
| 92 | import {
|
---|
| 93 | syncHistoryWithStore
|
---|
| 94 | } from 'react-router-redux';
|
---|
| 95 |
|
---|
| 96 | const history = syncHistoryWithStore(browserHistory, store, {
|
---|
| 97 | selectLocationState (state) {
|
---|
| 98 | return state.get('routing').toJS();
|
---|
| 99 | }
|
---|
| 100 | });
|
---|
| 101 | ```
|
---|
| 102 |
|
---|
| 103 | The `'routing'` path depends on the `rootReducer` definition. This example assumes that `routeReducer` is made available under `routing` property of the `rootReducer`.
|
---|