メインコンテンツへスキップ
非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

combineReducers(reducers)

概要

combineReducers ヘルパー関数は、値として異なる「スライスリデューサ」関数を持つオブジェクトを、Redux ToolkitのconfigureStore(または従来のcreateStoreメソッド)に渡せる単一の複合リデューサ関数に変換します。

生成された複合リデューサは、アクションがディスパッチされるたびに各スライスリデューサを呼び出し、その結果を単一のステートオブジェクトに集約します。これにより、リデューサロジックを独立した関数に分割し、それぞれが独自のステートスライスを管理できるようになります。

ヒント

この機能が必要になるケースは稀です。Redux ToolkitのconfigureStoreメソッドは、スライスリデューサのオブジェクトが渡されると自動的にcombineReducersを呼び出します:

const store = configureStore({
reducer: {
posts: postsReducer,
comments: commentsReducer
}
})

ルートリデューサを手動で構築する必要がある場合に限り、combineReducers()を明示的に呼び出せます。

ステートスライス

combineReducers()が生成するステートは、各リデューサのステートをcombineReducers()に渡されたキーで名前空間化します

例:

rootReducer = combineReducers({potato: potatoReducer, tomato: tomatoReducer})
// This would produce the following state object
{
potato: {
// ... potatoes, and other state managed by the potatoReducer ...
},
tomato: {
// ... tomatoes, and other state managed by the tomatoReducer, maybe some nice sauce? ...
}
}

渡されるオブジェクト内のリデューサキーを変更することでステートキー名を制御できます。例えばcombineReducers({ todos: myTodosReducer, counter: myCounterReducer })と呼び出すと、ステート構造は{ todos, counter }となります。

引数

  1. reducers (オブジェクト): 値として統合が必要な異なるリデューサ関数に対応するオブジェクト。
combineReducers({
posts: postsReducer,
comments: commentsReducer
})

渡されるすべてのリデューサが従うべきルールについては、下記の注意事項を参照してください。

戻り値

(関数): reducersオブジェクト内の全リデューサを実行し、同じ構造のステートオブジェクトを構築するリデューサ。

注意事項

この関数には若干の設計思想が反映されており、初心者が陥りやすい落とし穴を避けることに重点を置いています。そのため、ルートリデューサを手動で記述する場合には必須ではないルールの適用を試みます。

combineReducersに渡されるリデューサは次のルールを満たす必要があります:

  • 認識できないアクションに対しては、第一引数として渡されたstateをそのまま返すこと。

  • undefinedを返してはならない。早期returnによる誤った返値は発生しやすいため、combineReducersはエラーが別箇所で発生するのを許容せず、例外をスローします。

  • 渡されたstateundefinedの場合、そのリデューサ用の初期ステートを返すこと。前項のルールにより、初期ステートもundefinedであってはなりません。オプション引数構文で指定するのが便利ですが、第一引数がundefinedかどうかを明示的にチェックすることも可能です。

combineReducersはリデューサがこれらのルールに準拠しているか検証を試みますが、開発者自身がルールを理解し遵守するよう努める必要があります。combineReducersundefinedを渡すことでリデューサを検証します。これはRedux.createStore(combineReducers(...), initialState)で初期ステートを指定した場合でも実行されます。従って、自身のコードで実際にundefinedを受け取る意図がなくとも、必ずリデューサがundefinedをステートとして受け取った場合に正しく動作するようにしてください。

使用例

reducers/todos.js

export default function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text])
default:
return state
}
}

reducers/counter.js

export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}

reducers/index.js

import { combineReducers } from '@reduxjs/toolkit'
import todos from './todos'
import counter from './counter'

export default combineReducers({
todos,
counter
})

App.js

import { configureStore } from '@reduxjs/toolkit'
import reducer from './reducers/index'

const store = configureStore({
reducer
})
console.log(store.getState())
// {
// counter: 0,
// todos: []
// }

store.dispatch({
type: 'ADD_TODO',
text: 'Use Redux'
})
console.log(store.getState())
// {
// counter: 0,
// todos: [ 'Use Redux' ]
// }

活用のヒント

  • このヘルパーはあくまで便利機能に過ぎません!独自の動作をする combineReducersを自作したり、子リデューサーから手動でstateオブジェクトを組み立てたり、他の関数と同様に明示的にルートリデューサー関数を記述することも可能です。

  • combineReducersはリデューサー階層のどのレベルでも呼び出せます。必ずしもトップレベルで行う必要はありません。実際、複雑化した子リデューサーを独立した孫リデューサーに分割するため、あるいはさらに細かい単位で分割するために再び使用することも可能です。