ルートリデューサーでReduxの状態をリセットする方法
序章
レデューサーでReduxの状態を初期状態にリセットする必要があったことはありますか? 状態をリセットすることは、多くのアプリが行う必要があることです。 アプリの状態をリセットする必要がある典型的な例は、ユーザーがログアウトするときです。
この記事では、状態のリセットの集中化、レデューサーごとのリセットロジック、およびレデューサーのリセットからの除外について学習します。
前提条件
このチュートリアルに従うには、次のものが必要です。
- ReactとReduxにある程度精通している。 Reduxを使い始めた場合は、この投稿を参照できます。
このチュートリアルは、redux
v4.1.0で検証されました。
RESET_APP
の制限を理解する
最も単純なアプローチは、すべてのレデューサーにRESET_APP
条件を追加することです。
次の形状のusers
レデューサーについて考えてみます。
const usersDefaultState = [];
const users = (state = usersDefaultState, { type, payload }) => {
switch (type) {
case 'ADD_USER':
return [...state, payload];
default:
return state;
}
};
次に、usersDefaultState
を返すために、スイッチにRESET_APP
ケースを追加します。
const usersDefaultState = [];
const users = (state = usersDefaultState, { type, payload }) => {
switch (type) {
case 'RESET_APP':
return usersDefaultState;
case 'ADD_USER':
return [...state, payload];
default:
return state;
}
};
これは1つまたは2つのレデューサーでは許容されますが、実際のアプリでは、レデューサーごとに同じコードを繰り返すことになり、多くの場合、次のようになります。
const usersDefaultState = [];
const users = (state = usersDefaultState, { type, payload }) => {
switch (type) {
case 'RESET_APP':
return usersDefaultState;
case 'ADD_USER':
return [...state, payload];
default:
return state;
}
};
const articlesDefaultState = [];
const articles = (state = articlesDefaultState, { type, payload }) => {
switch (type) {
case 'RESET_APP':
return articlesDefaultState;
case 'ADD_ARTICLE':
return [...state, payload];
default:
return state;
}
};
DRY (繰り返しないでください)を覚えていますか? まあ、このコードは実際にはその原則に準拠しておらず、それは開発者として私たちが避けなければならないことです。
国家のリセットを一元化する
アプリを1か所でリセットするためのロジックを再利用する秘訣は、アプリのルートレデューサーの上にルートレデューサーを作成することです。 これは、レデューサーの上にあるレデューサーであり、その状態を確認し、必要に応じて適用します。
通常、combineReducers
関数を使用して、reduxストア用の単一のルートレデューサーを作成します。
import { combineReducers } from 'redux';
const usersDefaultState = [];
const users = (state = usersDefaultState, { type, payload }) => //...
const articlesDefaultState = [];
const articles = (state = articlesDefaultState, { type, payload }) => //...
const allReducers = combineReducers({
users,
articles
});
この場合、allReducers
は、ReduxのcreateStore
関数に渡すアプリのルートレデューサーです。
その上にラッピングルートレデューサーを作成するには、そのルートレデューサーを呼び出す関数を定義する必要があります。
const rootReducer = (state, action) => {
return allReducers(state, action);
}
現在、rootReducer
は、allReducers
呼び出しの間にある関数として機能しています。 その呼び出しの直前に、レデューサー呼び出しの前に適用される共通の機能を追加できます。 そして、アプリをリセットするために、undefined
に設定された状態を渡すことができます。
const rootReducer = (state, action) => {
if (action.type === 'RESET_APP') {
state = undefined;
}
return allReducers(state, action);
}
待って、何? なぜそれがアプリをリセットするのでしょうか? さて、レデューサーの定義を分析すると、次のようになります。
const users = (state = usersDefaultState, { type, payload }) => //...
この場合、state
パラメーターのデフォルト値はusersDefaultState
であり、関数のデフォルトパラメーターは、受信したパラメーター値がnull
ではなく、undefined
のみ)。 そのため、すべてのレデューサーが受け取る状態がデフォルトの状態です。
待って、状態を変えてみませんか? いいえ、状態参照をundefined
に変更しますが、変更しません。 状態の変更はReduxの原則に反することを忘れないでください。
レデューサーごとのリセットロジックの使用
rootReducer
を使用して集中リセットロジックを適用しても、他のレデューサーでRESET_APP
アクションのカスタム機能を使用できなくなることはありません。
たとえば、articles
レデューサーは、RESET_APP
がトリガーされたときに、デフォルト以外の状態を返す必要があるとします。
const articles = (state = articlesDefaultState, { type, payload }) => {
switch (type) {
case "RESET_APP":
return "App is reset";
case "ADD_ARTICLE":
return [...state, payload];
default:
return state;
}
};
重要なのは、デフォルトでは、すべてのレデューサーがデフォルトの状態を返すようにし、必要な場合にのみカスタムリセット動作を行うことです。
レデューサーをリセットから除外する
一部の特定のレデューサーがリセットされるのを避けたい場合があります。 除外したい状態のスライスを保持することで、それを防ぐことができます。
たとえば、articles
レデューサーをリセットから除外する場合:
const rootReducer = (state, action) => {
if (action.type === 'RESET_APP') {
const { articles } = state;
state = { articles };
}
return allReducers(state, action);
};
ここで何が起こっているのですか? combineReducers
関数は、レデューサーを組み合わせて対応する状態を渡すため、各レデューサーはスコープ内の状態の一部のみを持ちます。
この場合、state = { articles }
で状態のarticles
部分を選択すると、関数allReducers
はstate.articles
をarticles
レデューサーに渡します。 state.users
からusers
レデューサー。 state.users
はundefined
であり、state.articles
はそうではないため、ユーザーレデューサーのみがリセットされます。
結論
この記事では、状態のリセットの集中化、レデューサーごとのリセットロジック、およびレデューサーのリセットからの除外について学習しました。
通常、コードの重複を回避する方法は複数ありますが、実際にDRYの原則に従うと、コードがより理解しやすく、保守しやすくなります。