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

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

リデューサーの基本構造とステートの形状

リデューサーの基本構造

まず最初に理解すべき重要な点は、アプリケーション全体で実際には単一のリデューサー関数しか存在しないということです。これはcreateStoreの第一引数として渡す関数であり、この単一のリデューサー関数は最終的に以下の処理を行う必要があります:

  • リデューサーが初めて呼び出される時、state値はundefinedになります。リデューサーは受信アクションを処理する前にデフォルトのステート値を提供してこのケースを処理する必要があります

  • 前回のステートとディスパッチされたアクションを確認し、どのような処理が必要かを判断する必要があります

  • 実際に変更が必要な場合、更新されたデータで新しいオブジェクトや配列を作成して返す必要があります

  • 変更が不要な場合、既存のステートをそのまま返すべきです

リデューサーロジックを記述する最もシンプルな方法は、すべてを単一の関数宣言にまとめることです。例えば:

function counter(state, action) {
if (typeof state === 'undefined') {
state = 0 // If state is undefined, initialize it with a default value
}

if (action.type === 'INCREMENT') {
return state + 1
} else if (action.type === 'DECREMENT') {
return state - 1
} else {
return state // In case an action is passed in we don't understand
}
}

このシンプルな関数はすべての基本要件を満たしています。存在しない場合はデフォルト値を返してストアを初期化し、アクションタイプに基づいて必要な更新の種類を判断して新しい値を返し、処理が不要な場合は前回のステートを返します

このリデューサーには簡単な改良を加えられます。まず、if/else文の繰り返しはすぐに煩わしくなるため、代わりにswitch文を使うのが一般的です。次に、デフォルトのパラメータ値を使用して初期の「既存データなし」ケースを処理できます。これらの変更を加えると、リデューサーは次のようになります:

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

これが典型的なReduxリデューサー関数の基本構造です

ステートの基本形状

Reduxではアプリケーションを管理すべきデータの観点から考えることが推奨されます。任意の時点でのデータはアプリケーションの「ステート」であり、その構造と編成は一般的に「形状」と呼ばれます。ステートの形状はリデューサーロジックの構築方法に大きな影響を与えます

Reduxステートは通常、ステートツリーの最上位にプレーンなJavaScriptオブジェクトを持ちます(単一の数値や配列、特殊なデータ構造など他の型も可能ですが、ほとんどのライブラリは最上位値がプレーンオブジェクトであることを前提としています)。この最上位オブジェクト内でデータを整理する最も一般的な方法は、サブツリーに分割することです。各最上位キーは関連データの「ドメイン」や「スライス」を表します。例えば基本的なTodoアプリのステートは次のようになります:

{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}

この例では、todosvisibilityFilterはどちらもステートの最上位キーであり、各々が特定の概念に関するデータの「スライス」を表しています

ほとんどのアプリケーションは複数のデータ型を扱い、それらは大きく3つのカテゴリに分類できます:

  • ドメインデータ: アプリケーションが表示・使用・変更する必要があるデータ(例: 「サーバーから取得したすべてのTodo」)

  • アプリケーションステート: アプリケーションの動作に特有のデータ(例: 「Todo #5が現在選択中」「Todo取得リクエスト処理中」)

  • UIステート: UIの現在の表示状態を表すデータ(例: 「Todo編集モーダルダイアログが開いている」)

ストアはアプリケーションの中核を表すため、ステートの形状はUIコンポーネントツリーではなく、ドメインデータとアプリケーションステートに基づいて定義するべきです。例えばstate.leftPane.todoList.todosのような形状は避けるべきです。なぜなら「todos」の概念はUIの一部ではなくアプリケーション全体の中核だからです。代わりにtodosスライスはステートツリーの最上位に配置する必要があります

UIツリーとステートの形状が1対1で対応することは めったに ありません。例外として、UIデータのさまざまな側面を明示的にReduxストアで追跡している場合が考えられますが、その場合でもUIデータの形状とドメインデータの形状はおそらく異なるでしょう。

典型的なアプリのステート形状は、おおよそ次のようになります:

{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}