Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

correct usage of reduce-reducers

Tags:

redux

reducers

I don't understand what reduce-reducers is meant for. Should it be used in the case that I have 2 reducer functions containing the same action?

function reducerA(state, action){    switch(action.type):        ...        case 'SAME_ACTION': {...state, field: state.field+1} }  function reducerB(state, action){    switch(action.type):        ...        case 'SAME_ACTION': {...state, field: state.field*2} } 

So if I call reduceReducer on reducerA and reducerB and action 'SAME_ACTION' is invoked for {field: 0} then I would have a next state {field: 2}?

Also it seems to me that it kind of concatenates reducers (meaning merging them under one key).

Am I right or does reduceReducer serve a different purpose?

like image 883
Amio.io Avatar asked Jul 29 '16 07:07

Amio.io


People also ask

What is the usage of reducer?

A reducer is a function that determines changes to an application's state. It uses the action it receives to determine this change. We have tools, like Redux, that help manage an application's state changes in a single store so that they behave consistently.

What is the use of reducers in react?

The reducer function uses the action object and performs a state update, returning the new state. React then checks whether the new state differs from the previous one. If the state has been updated, React re-renders the component and useReducer() returns the new state value: [newState, ...]

What is the purpose of reducer in Redux?

In Redux, a reducer is a pure function that takes an action and the previous state of the application and returns the new state. The action describes what happened and it is the reducer's job to return the new state based on that action. It may seem simple, but it does have to be a pure function with no side effects.


1 Answers

The difference is:

  • combineReducers creates nested state
  • reduceReducers creates flat state

Consider following reducers. There are no action types to make things simpler:

// this reducer adds a payload to state.sum  // and tracks total number of operations function reducerAdd(state, payload) {   if (!state) state = { sum: 0, totalOperations: 0 }   if (!payload) return state    return {     ...state,     sum: state.sum + payload,     totalOperations: state.totalOperations + 1   } }  // this reducer multiplies state.product by payload // and tracks total number of operations function reducerMult(state, payload) {   if (!state) state = { product: 1, totalOperations: 0 }   if (!payload) return state    // `product` might be undefined because of    // small caveat in `reduceReducers`, see below   const prev = state.product || 1    return {     ...state,     product: prev * payload,     totalOperations: state.totalOperations + 1   } } 

combineReducers

Each reducer gets an independent piece of state (see also http://redux.js.org/docs/api/combineReducers.html):

const rootReducer = combineReducers({   add: reducerAdd,   mult: reducerMult })  const initialState = rootReducer(undefined) /*  * {  *   add:  { sum: 0, totalOperations: 0 },  *   mult: { product: 1, totalOperations: 0 },  * }  */   const first = rootReducer(initialState, 4) /*  * {  *   add:  { sum: 4, totalOperations: 1 },  *   mult: { product: 4, totalOperations: 1 },  * }  */     // This isn't interesting, let's look at second call...  const second = rootReducer(first, 4) /*  * {  *   add:  { sum: 8, totalOperations: 2 },  *   mult: { product: 16, totalOperations: 2 },  * }  */ // Now it's obvious, that both reducers get their own  // piece of state to work with 

reduceReducers

All reducers share the same state

const addAndMult = reduceReducers(reducerAdd, reducerMult)   const initial = addAndMult(undefined) /*   * {  *   sum: 0,  *   totalOperations: 0  * }  *  * First, reducerAdd is called, which gives us initial state { sum: 0 }  * Second, reducerMult is called, which doesn't have payload, so it   * just returns state unchanged.   * That's why there isn't any `product` prop.  */   const next = addAndMult(initial, 4) /*   * {  *   sum: 4,  *   product: 4,  *   totalOperations: 2  * }  *  * First, reducerAdd is called, which changes `sum` = 0 + 4 = 4  * Second, reducerMult is called, which changes `product` = 1 * 4 = 4  * Both reducers modify `totalOperations`  */   const final = addAndMult(next, 4) /*   * {  *   sum: 8,  *   product: 16,  *   totalOperations: 4  * }  */ 

Use cases

  • combineReducers - each reducer manage own slice of state (e.g. state.todos and state.logging). This is useful when creating a root reducer.
  • reduceReducers - each reducer manage the same state. This is useful when chaining several reducers which are supposed to operate over the same state (this might happen for example when combining several reducer created using handleAction from redux-actions)

The difference is obvious from the final state shape.

like image 50
Tomáš Ehrlich Avatar answered Sep 16 '22 20:09

Tomáš Ehrlich