Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
133
Help us understand the problem. What is going on with this article?
@kuy

Reduxにおけるreducer分割とcombineReducersについて

More than 5 years have passed since last update.

2015-08-28 11:06 合成された初期状態ツリーの出力結果を追加

分割されたreducerの初期状態ツリー

Reduxの原則の1つであるグローバルな状態ツリーがすべてのソースとなるという点。
理屈ではわかるんだけど、いくつかコンポーネントを作っていくと常に大きなツリーが渡されるってのがとても扱いづらく感じる。つまり、何かアクションを受け取ってそれを状態ツリーに反映させるとき、ほとんどのケースにおいてツリーの一部だけを更新して、それ以外はいじらないことが多いからだ。

Reduxリポジトリのasyncのサンプルコードを追っていくと、reducers/index.jsの部分がよくわからなかった。
他のサンプルだと初期状態ツリーは定数として定義してreducerのデフォルト引数に指定していることが多かったが、asyncではまずそれがない。
そしてなにより状態ツリーはグローバルなものが1つで、それがすべてであるという説明を読んでいたので、postsByRedditは文字列、selectedRedditはオブジェクトというように初期状態の構造が異なっていることには混乱した。

そうなると怪しいのはcombineReducersになる。最初に名前を見た時、単に1つずつ実行しているだけだろうと思ったけど実際にはそれ以外にもやっていた。そしてそれが各reducerにおいて初期状態の構造が異なっている理由だった。

combineReducersがやっていること

combineReducersの処理の本筋部分だけを取り出すと

  • 各reducerを呼び出して初期状態を取り出す
  • 初期状態をまとめて初期状態ツリーを作る
  • reducerの処理をまとめたcombination関数を返す

となっていて、combineReducersが初期状態ツリーの生成も担っていた。

さらにcombination関数の処理について

combineReducersが返すcombination関数はreducer名をキーにした状態ツリーから、そのreducerの部分状態を取り出して渡す。戻ってきた新しい部分状態はやはりreducer名をキーにしてまた1つの状態ツリーにまとめられて、最終的なreducerの戻り値となる。

function reducerA(state = 'hoge', action) {
  switch (action.type) {
    case 'ACTION_X':
      return 'foobar';
  }
  return state;
}

function reducerB(state = { flag: false, items: [] }, action) {
  switch (action.type) {
    case 'ACTION_Y':
      return Object.assign({}, state, { flag: true });
  }
  return state;
}

let rootReducer = combineReducers({ reducerA, reducerB });

// stateとしてundefinedを渡して初期状態ツリーを取り出す
console.log(rootReducer(undefined, { type: null }));

実行すると以下の初期状態ツリーが出てくる。

{
  "reducerA": "hoge",
  "reducerB": {
    "flag": false,
    "items": []
  }
}

reducerをどう分割していくか

combineReducersを使うことでreducerごとに別々の名前空間で処理が実行されているようなものなので(chrootみたいな感じ)、reducerの分割単位は状態ツリーのどの部分ツリーをスコープとするかがポイントになるようだ。

基本的には個々のreducerは最小限の部分ツリーで動くように作って、どうしてもツリーを横断的に処理する必要があるものについてはそれらを含むちょっと大きめのツリーを渡すreducerに任せる、って感じで作っていくといいのかな。

133
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kuy

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
133
Help us understand the problem. What is going on with this article?