web-dev-qa-db-ja.com

reduce-reducerの正しい使用法

reduce-reducers の意味がわかりません。同じアクションを含む2つのリデューサー関数がある場合に使用する必要がありますか?

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

reduceReducerおよびreducerAreducerBを呼び出し、{field: 0}に対してアクション 'SAME_ACTION'が呼び出された場合、次の状態は{field: 2}になりますか?

また、それは一種のレデューサーを連結しているように思えます(1つのキーの下でそれらをマージすることを意味します)。

私は正しいですか、またはreduceReducerは別の目的に役立ちますか?

27
Amio.io

違いは:

  • combineReducersネストされた状態を作成します
  • reduceReducersは、flat状態を作成します

次の減速機を検討してください。物事を簡単にするためのアクションタイプはありません。

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

コンバイン

各レデューサーは、独立した状態を取得します( 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 = 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
 * }
 */

ユースケース

  • combineReducers-各レデューサーは、状態の独自のスライスを管理します(例:state.todosおよびstate.logging)。これは、rootレデューサーを作成するときに役立ちます。
  • reduceReducers-各レデューサーは同じ状態を管理します。これは、同じ状態で動作するはずの複数のレデューサーをチェーンする場合に便利です(たとえば、 redux-actions からhandleActionを使用して作成された複数のレデューサーを組み合わせる場合に発生する可能性があります)

違いは、最終状態の形状から明らかです。

注意事項

reduceReducersには小さな注意事項があります:state = undefinedを指定してfinalレデューサーを呼び出すと、初期状態を返す必要があります。ただし、チェーンの最初のレデューサーのみがundefinedを取得し、他のすべてのレデューサーは最初のレデューサーから状態を受け取ります。

72
Tomáš Ehrlich

また、reduce-reducerが解決しようとしているものがわかりません。 @Tomášによって記述されたユースケースは、単純なReducerによって実現できます。結局のところ、Reducerはアプリの状態とアクションを受け入れ、新しいアプリの状態を含むオブジェクトを返すだけの関数です。たとえば、reduxが提供するcomposeReducersを使用する代わりに、以下を実行できます。

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

そしてもちろんここでは、レデューサーはアプリの状態全体を受け入れて、担当するスライスのみを返します。繰り返しますが、これは単なる関数であり、好きなようにカスタマイズできます。それについてもっと読むことができます こちら

0
Behnam Rasooli