[解決済み] Redux Reducerでストアの初期状態を読み込む
質問
Reduxアプリの初期状態は、2つの方法で設定することができます。
-
の第2引数として渡す。
createStore
( ドキュメント・リンク ) - これを(サブ)リデューサの第一引数として渡します ( ドキュメントリンク )
ストアに初期状態を渡す場合、ストアからその状態を読み取り、リデューサの最初の引数にするにはどうすればよいでしょうか。
どのように解決するのですか?
TL;DR
なし
combineReducers()
などの手動のコードでinitialState
は常にstate = ...
が勝つので、reducerではstate
はリデューサに渡される はinitialState
であり はundefined
であるため、ES6の引数構文はこの場合適用されません。とは
combineReducers()
では、より微妙な挙動になります。で状態が指定されているリデューサはinitialState
で指定されたリデューサは、そのstate
. 他のレデューサはundefined
となり、そのため にフォールバックすることになります。state = ...
というデフォルトの引数が指定されます。一般的には
initialState
はリデューサによって指定された状態よりも優先されます。これにより、リデューサは意味のある初期データを指定することができます リデューサにとって をデフォルトの引数として指定できますが、ストアを永続的なストレージやサーバーからハイドレートするときに、既存のデータを (完全にまたは部分的に) ロードすることもできます。
まず、reducerを1つ持っている場合を考えてみましょう。
を使わないとします。
combineReducers()
.
そうすると、reducerは以下のようになります。
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
}
では、これでお店を作るとしましょう。
import { createStore } from 'redux';
let store = createStore(counter);
console.log(store.getState()); // 0
初期状態は0です。なぜか? なぜなら、第二引数の
createStore
は
undefined
. これは
state
に渡されるものです。Reduxが初期化されるとき、状態を満たすために「ダミー」のアクションがディスパッチされます。そのため、あなたの
counter
で呼び出されたリデューサは
state
と同じ
undefined
.
これはまさにデフォルトの引数を「発動」させるケースです。
したがって
state
は現在
0
は、デフォルトの
state
の値 (
state = 0
). この状態(
0
)が返されます。
別のシナリオを考えてみましょう。
import { createStore } from 'redux';
let store = createStore(counter, 42);
console.log(store.getState()); // 42
なぜ
42
でなく
0
でなく、今回は?なぜなら
createStore
が呼び出されたからです。
42
を第二引数として呼び出す。この引数は
state
になり、ダミーアクションと一緒にreducerに渡されます。
今回は
state
は未定義ではなく、(それは
42
!)なので、ES6 のデフォルトの引数シンタックスは何の効果もありません。
は
state
は
42
であり、かつ
42
がreducerから返されます。
それでは、例えば
combineReducers()
.
レデューサーが2つありますね。
function a(state = 'lol', action) {
return state;
}
function b(state = 'wat', action) {
return state;
}
で生成されたリデューサは
combineReducers({ a, b })
はこのようになります。
// const combined = combineReducers({ a, b })
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
もし
createStore
を呼び出すと
initialState
を初期化します。
state
から
{}
. したがって
state.a
となり
state.b
となるのは
undefined
を呼び出すまでに
a
と
b
のレデューサーです。
ともに
a
と
b
レジューサーは
undefined
として
その
state
引数を指定し、デフォルトの
state
の値が指定されていれば、それが返されます。
このように、結合されたreducerが返す
{ a: 'lol', b: 'wat' }
の状態オブジェクトを最初の起動時に返します。
import { createStore } from 'redux';
let store = createStore(combined);
console.log(store.getState()); // { a: 'lol', b: 'wat' }
別のシナリオを考えてみましょう。
import { createStore } from 'redux';
let store = createStore(combined, { a: 'horse' });
console.log(store.getState()); // { a: 'horse', b: 'wat' }
今度は
initialState
を引数として
createStore()
. 結合されたリデューサから返される状態
を結合する
に指定した初期状態を
a
レデューサに指定した初期状態と
'wat'
というデフォルトの引数が指定されています。
b
reducerは自分自身を選んだ。
結合されたreducerが何をするのか思い出してみましょう。
// const combined = combineReducers({ a, b })
function combined(state = {}, action) {
return {
a: a(state.a, action),
b: b(state.b, action)
};
}
この場合
state
にフォールバックしないように指定されました。
{}
. を持つオブジェクトでした。
a
と等しいフィールドを持つオブジェクトでした。
'horse'
と同じですが
b
フィールドはありません。このため
a
を受け取ったレデューサは
'horse'
をその
state
として、喜んで返しましたが
b
を受け取ったレジューサーは
undefined
をその
state
として返され、その結果
その考え
のデフォルトの
state
(この例では
'wat'
). このようにして
{ a: 'horse', b: 'wat' }
を返します。
まとめると、Reduxの規約を守り、リデューサーが呼び出されたときに初期状態を
undefined
を
state
引数として指定します(最も簡単な実装は
state
ES6のデフォルトの引数値です)、複合リデューサーのための素敵な便利な振る舞いを手に入れることになります。
の対応する値を好むようになります。
initialState
オブジェクトに渡す
createStore()
関数に渡すことができますが、何も渡さなかったり、 対応するフィールドが設定されていない場合は、デフォルトの
state
の引数が代わりに選ばれます。
このアプローチは、既存のデータの初期化と水増しの両方を提供しつつ、データが保存されていない場合は個々のリデューサに状態をリセットさせるので、うまく機能します。もちろん、このパターンを再帰的に適用することも可能で、その場合は
combineReducers()
を使うことができるので、このパターンを再帰的に適用することもできますし、リデューサを呼び出して状態ツリーの関連部分を与えることで、リデューサを手動で構成することもできます。
関連
-
[解決済み] Node.jsを使うタイミングをどう判断するか?
-
[解決済み] Reduxのアクションをタイムアウトでディスパッチする方法とは?
-
[解決済み] Reduxの非同期フローになぜミドルウェアが必要なのか?
-
[解決済み] Reduxストアの状態をリセットする方法とは?
-
[解決済み】Redux - 複数店舗、なぜダメなの?
-
[解決済み】React-ReduxとmapStateToProps()を理解する。)
-
[解決済み] AngularJSのエラーです。Cross Origin リクエストはプロトコルスキーム http, data, chrome-extension, https に対してのみサポートされています。
-
[解決済み] WebStormで未解決の変数が大量にある場合の警告に対処する方法は?
-
[解決済み] jQueryで入力ファイルが空かどうかをチェックする方法
-
[解決済み] JavaScriptでjson-objectのキーを取得する [重複].
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】ReduxアプリでlocalStorageに書き込む場所は?
-
[解決済み] JSのDateからDay名
-
[解決済み] チェックボックスが選択されているかどうかを確認するjQuery
-
[解決済み] reactのrender関数でdynamic hrefを作成するには?
-
[解決済み] コールバック地獄とは何か、RXはそれをどのように、そしてなぜ解決するのか?
-
[解決済み] JavaScriptでjson-objectのキーを取得する [重複].
-
[解決済み] 文字列とラベルのローカライズとグローバリゼーションのベストプラクティス【終了しました
-
[解決済み] JavaScriptのArray.sort()メソッドでシャッフルするのは正しいのか?
-
[解決済み] JavaScriptの文字列プリミティブとStringオブジェクトの違いは何ですか?
-
[解決済み] JavaScriptデータフォーマット/プリティプリンタ