One Step Ahead

プログラミングやエンジニアリング全般について書いていきます

複数のReducerが存在する場合に渡されるActionたち

分かりづらいRedux


Reactの「state」管理といえば「Redux」という組みわせが多いのではないだろうか?
自分もこの組み合わせで「Redux」に出会ったが、Reactに比較するとはどうも分かりづらい。 (バカな自分にとっては非常に学習コストが高かった...)
とりあえず使うことはできるが「理解している」のかと言われてしまうと言葉に詰まる。

その中でも、最近疑問に思ったのはReducerとActionの関係。 特にReducerが複数存在し、combineされた後の挙動がどうしてもしっくりこなかった。
「複数Action、複数Reducerが存在するのに発行されたActionはどうやって、自分自身が処理対象となっているReducerを特定しているのだろう?」と。

単一のActionとReducerの関係


1対1となっている場合は、割とすんなり理解できる。Sampleコードとして下記のようなコードが示されることが多い。
特定のTypeをもつActionとそれをハンドリングするReducer。

// Action
const sampleAction_A = (arg) => ({
  type: 'SAMPLE_ACTION_A',
  payload: {
    arg
  },
  error: false
})

const sampleAction_B = (arg) => ({
  type: 'SAMPLE_ACTION_B',
  payload: {
    arg
  },
  error: false
})

// Reducer
function sampleA_Reducer(state, action) {
  switch(action.type) {
    case 'SAMPLE_ACTION_A':
      return {
        node: action.payload.arg
      }
    case 'SAMPLE_ACTION_B':
      return {
        node: action.payload.arg
      }
    default:
        return state
  }
}

この場合はActionをハンドリングするReducerが一つであるため、発行されたActionが渡されるReducerが「sampleA_Reducer」だと分かる。 よく書籍で説明される「指定のTypeをもつAction発行され、Reducerによって状態が変化します。」という説明が理解できる。
しかし、ReducerとActionが増えてしまうと上記の説明だけでは、理解したと私的には言い難い...

複数のActionとReducerの関係


さて本題に入るが、結論から言うと「ActionはReducerを特定などしていない。」が正解だった。
発行されたActionはcombineされたすべてのReducerに対して渡されていく。

疑問に思ったのは下記のような場合。
通常Actionに依存関係がなく、ハンドリングとしても分けられる場合には、Actionとそれに対応するReducerを分けて作成する。

// Action
const actionA = (args) => ({
  type: 'A_ACTION',
  payload: {
    args
  },
  error: false
})

const actionB = (args) => ({
  type: 'B_ACTION',
  payload: {
    args
  },
  error: false
})

// Reducer
export const actionA_Reducer = (state, action) => {
  switch(action.type) {
    case 'A_ACTION':
      return {
        node: action.payload.args
      }
    default:
      return state
  }
}

export const actionB_Reducer = (state, action) => {
  switch(action.type) {
    case 'B_ACTION':
      return {
        node: action.payload.args
      }
    default:
      return state
  }
}

そしてこれらのReducerをcombineしてRootReducerを作成する。

// RootReducerを作成する
const rootReducer = combineReducers({
  actionA_Reducer,
  actionB_Reducer
})

このような場合に「A_ACTION」が発行されると、storeに紐づいているすべてのReducerに対して、Actionが渡されていく。
これはVS Codeなどを使用してDebugすると簡単に確かめることができる。

変わらないことも重要


Reducerを特定しない。」「すべてのReducerに渡される」というのであれば適切に対象Actionを処理することも大切だが、不用意な変化をさせないということも重要。
何冊か「React-Redux」に関する書籍は読んだが、ここら辺は自分が覚えている限りでは詳細な記載がなかったので、やっぱり疑問に思ったことは時間を作ってでも調べた方がいいね。