|
| 1 | +# Composite Reducer |
| 2 | + |
| 3 | +[](https://www.npmjs.com/package/@voiceflow/composite-reducer) |
| 4 | +[](https://www.npmjs.com/package/@voiceflow/composite-reducer) |
| 5 | + |
| 6 | +[What are Reducers?](https://css-tricks.com/understanding-how-reducers-are-used-in-redux/) |
| 7 | + |
| 8 | +Allows reducers for specific properties of a state - better organization for reducers of complex or deeply nested objects. |
| 9 | + |
| 10 | +> Works well with state management solutions such as [Redux](https://redux.js.org/) or [React Context](https://reactjs.org/docs/context.html) + [useReducer](https://reactjs.org/docs/hooks-reference.html#usereducer) hook. |
| 11 | +
|
| 12 | +Similar to the [`combineReducers`](https://redux.js.org/api/combinereducers) function in redux. But instead of combining many equal top level reducers, has a main reducer and attaches other reducers for properties of the main state. |
| 13 | + |
| 14 | +## Why? |
| 15 | + |
| 16 | +Say there is a state that looks like this: |
| 17 | + |
| 18 | +``` |
| 19 | +{ |
| 20 | + name: "voiceflow", |
| 21 | + type: "startup", |
| 22 | + settings: { |
| 23 | + website: "voiceflow.com" |
| 24 | + } |
| 25 | +} |
| 26 | +``` |
| 27 | + |
| 28 | +If a reducer is created for this state, to change the `website`, I would need a dedicated action to update it, and construct a new state with something messier like this: |
| 29 | + |
| 30 | +``` |
| 31 | +{ |
| 32 | + ...state, |
| 33 | + settings: { |
| 34 | + ...state.settings, |
| 35 | + website: action.payload |
| 36 | + } |
| 37 | +} |
| 38 | +``` |
| 39 | + |
| 40 | +With `composite-reducer`, the `settings` sub-state can be abstracted into it's own dedicated reducer, separate from the main one. |
| 41 | + |
| 42 | +``` |
| 43 | +const reducer = compositeReducer(mainReducer, { |
| 44 | + settings: settingsReducer |
| 45 | +}); |
| 46 | +``` |
| 47 | + |
| 48 | +The dedicated reducer updates/works with a smaller, more concise state. |
| 49 | + |
| 50 | +The main reducer can still act on the property if it has to. |
| 51 | + |
| 52 | +Along with [`combinedReducer`](), this encourges the overall reducer to be cleaner/better organized. |
| 53 | + |
| 54 | +## Example |
| 55 | + |
| 56 | +``` |
| 57 | +import compositeReducer from 'composite-reducer'; |
| 58 | +
|
| 59 | +const mainReducer = (state, action) => { |
| 60 | + // do reducer stuff here |
| 61 | + return state; |
| 62 | +}; |
| 63 | +const propertyOneReducer = (state, action) => { |
| 64 | + // state is in the shape of propertyOne |
| 65 | + // do reducer stuff here |
| 66 | + return state; |
| 67 | +}; |
| 68 | +
|
| 69 | +const propertyTwoReducer = (state, action) => { |
| 70 | + // state is in the shape of propertyTwo |
| 71 | + // do reducer stuff here |
| 72 | + return state; |
| 73 | +}; |
| 74 | +
|
| 75 | +const reducer = compositeReducer(mainReducer, { |
| 76 | + propertyOne: subpropertyOneReducer, |
| 77 | + propertyTwo: subpropertyTwoReducer, |
| 78 | +}) |
| 79 | +``` |
| 80 | + |
| 81 | +## Installation |
| 82 | + |
| 83 | +To use `composite-reducer`, install it as a dependency: |
| 84 | + |
| 85 | +```bash |
| 86 | +# If you use npm: |
| 87 | +npm install @voiceflow/composite-reducer |
| 88 | + |
| 89 | +# Or if you use Yarn: |
| 90 | +yarn add @voiceflow/composite-reducer |
| 91 | +``` |
| 92 | + |
| 93 | +This assumes that you’re using a package manager such as [npm](http://npmjs.com/). |
| 94 | + |
| 95 | +## License |
| 96 | + |
| 97 | +[MIT](LICENSE.md) |
0 commit comments