正确使用减速器

时间:2016-07-29 07:20:30

标签: redux reducers

我不明白reduce-reducers的含义是什么。如果我有2个包含相同动作的reducer功能,它是否可以使用?

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}
}

因此,如果我在reduceReducerreducerA上拨打reducerB,并为{field: 0}调用“SAME_ACTION”操作,那么我会有下一个状态{field: 2}

在我看来,它有点连接缩减器(意味着将它们合并在一个键下)。

我是对的还是reduceReducer用于不同的目的?

2 个答案:

答案 0 :(得分:62)

区别在于:

  • combineReducers创建嵌套状态
  • reduceReducers创建平面状态

考虑以下减速器。没有任何动作类型可以简化事情:

// 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

每个reducer都有一个独立的状态(另见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

所有减少者分享相同的州

const addAndMult = reducerReduce(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
 * }
 */

用例

  • combineReducers - 每个reducer管理自己的状态片段(例如state.todosstate.logging)。这在创建 root reducer时非常有用。
  • reduceReducers - 每个reducer管理相同的状态。当链接几个应该在相同状态下运行的reducers时,这很有用(例如,当组合使用redux-actions中的handleAction创建的多个reducer时可能会发生这种情况)

从最终的状态形状来看,差异很明显。

注意事项

reduceReducers中有一个小警告:当使用state = undefined调用最终的reducer时,它应该返回初始状态。但是,只有链中的第一个缩减器获得undefined,所有其他缩减器将从第一个缩减器接收状态。

答案 1 :(得分:-1)

我也没有得到减速器试图解决的问题。 @Tomáš描述的用例可以通过一个简单的Reducer来实现。毕竟,Reducer只是一个接受应用程序状态和操作并返回包含新应用程序状态的对象的函数。例如,您可以执行以下操作,而不是使用redux提供的CombineReducers:

import combinationReducer from "./combinationReducer";
import endOfPlayReducer from "./endOfPlayReducer";
import feedbackReducer from "./feedbackReducer";

function combineReducers(appState, action) {
  return {
    combination: combinationReducer(appState, action),
    feedbacks: feedbackReducer(appState, action),
    endOfPlay: endOfPlayReducer(appState, action)
  };
}

当然,在这里,您的reducer接受整个应用程序状态,仅返回他们负责的切片。同样,它只是一个功能,您可以随时自定义它。您可以详细了解here