Reduxストアを永続化する方法
Reduxは複雑なアプリケーションにおける状態管理を簡素化します。Reduxストアはアプリの全状態を含んでいるため、それを永続化することでユーザーのセッションを保存し、復元することができます。
あなたのストアを作成する
私たちはあなたがReduxの基本を理解していると仮定します。
このチュートリアルでは、ベアボーンストアと単純なリデューサーを使用します。
import {createStore} from "redux";
const state = {authenticated: false};
const reducer = (state, action) => ({...state, ...action});
const store = createStore(reducer, state);
この些細な例は、ログインしているかどうかを追跡できるReduxストアの準備をします。ほとんどのユーザーは、アプリに戻ったときにサインインしたままであることを期待します。現在、状態はアプリが読み込まれるたびに新たに作成されるため、ユーザーは現在のセッション内でのみ認証されたままとなります。
Redux Persistを追加する
Redux Persistは、ストアに持続性を追加するための人気のあるライブラリです。このライブラリは、状態が更新されるたびに自動的にストアを保存します。あなたのアクションやリデューサーに持続性のコードを書く必要はありません。
まずnpmを使用してRedux Persistをインストールします:
npm install redux-persistあなたは今、ライブラリをストアに接続する必要があります。ルートリデューサーをRedux PersistのpersistReducer関数でラップします。これにより、Redux Persistはストアにディスパッチするアクションを検査できるようになります。また、永続性を開始するためにpersistStore()を呼び出す必要があります。
import {createStore} from "redux";
import {persistStore, persistReducer} from "redux-persist";
import storage from "redux-persist/lib/storage";
const state = {authenticated: false};
const reducer = (state, action) => ({...state, ...action});
const persistConfig = {
key: "root",
storage
};
const persistedReducer = persistReducer(persistConfig, reducer);
const store = createStore(persistedReducer, state);
const persistor = persistStore(store);
この設定は現在使用する準備が整いました。わずか数行のコードで、Reduxの状態の変更が自動的に保存されることを確実にしました。ユーザーはアプリを再読み込みするたびにサインアウトされることはなくなります。
私たちのリデューサーは、永続性サポートを含むために persistReducer() によって強化されています。この新しくラップされたリデューサーは、元のリデューサーの代わりに createStore() に渡されます。最後に、永続性を有効にするためにストアインスタンスを渡して persistStore() が呼び出されます。
Redux Persistの設定
persistReducer() 関数は、最初のパラメータとして設定オブジェクトを受け取ります。key と storage プロパティを指定する必要があります。
key は、永続化されたオブジェクトの最上位プロパティの名前を設定します。あなたのストアの状態は、このプロパティの値として保存されます。
storageは使用するストレージエンジンを定義します。Redux Persistは環境に応じて複数の異なるストレージバックエンドをサポートします。ウェブ使用の場合、localStorageおよびsessionStorage APIの両方が基本的なクッキーとともにサポートされています。React Native、Node.js、Electron、その他のいくつかのプラットフォームのオプションも利用可能です。
ストレージエンジンは、そのパッケージからインポートすることで定義します。その主要なAPIを実装するオブジェクトは、Redux Persistのstorageオプションとして渡す必要があります。
独自のストレージエンジンを実装してカスタムの永続化メカニズムを使用できます。setItem()、getItem()、およびremoveItem() メソッドを持つオブジェクトを作成してください。Redux Persistは非同期のため、各メソッドは操作が完了した時に解決されるPromiseを返す必要があります。
パーシスターオブジェクト
persistStore() から返される persistor オブジェクトには、永続性を管理するためのいくつかのユーティリティメソッドがあります。
それぞれ pause() と resume() メソッドを使用して、永続性を一時停止および再開できます。flush() を使ってストレージエンジンへの即時書き込みを強制することもできます。これは、特定の操作の後に状態が永続化されることを保証する必要がある場合に便利です。
ストレージエンジンから永続データをすべて消去するには、.purge()を使用できます。しかし、ほとんどの場合、これは避けるべきです - ストアをクリアするためにReduxアクションを使用すべきです。そうすれば、永続データにも自動的に伝播します。
州の和解
Redux Persistは、永続化された状態からストアを水和するための3つの異なる方法をサポートしています。水和は、persistStore()を呼び出し、ストレージエンジンに既存のデータが見つかったときに自動的に発生します。Redux Persistは、その初期データをストアに注入する必要があります。
デフォルトの戦略は、オブジェクトを1レベル深くまでマージすることです。ネストされたオブジェクトはマージされず、受け入れられる変更は状態にすでにあるものを上書きします。
- 持続した状態:
{"demo": {"foo": "bar"}} - ストアに表示:
{"デモ": {"例": "テスト"}} - 結果として得られたハイドレートストア:
{"demo": {"foo": "bar"}}
オプションで、オブジェクトを指定された深さまでマージするように切り替えることができます。新しいステートリコンシリエーターをインポートし、ストアの設定に追加してください:
// usual imports omitted
import autoMergeLevel2 from "redux-persist/lib/stateReconciler/autoMergeLevel2";
const persistConfig = {
key: "root",
storage,
stateReconciler: autoMergeLevel2
};
// store configuration omitted
autoMergeLevel2を使って上記の例をハイドレートすると、結果は以下のようになります:
- 持続した状態:
{"demo": {"foo": "bar"}} - ストアの状態:
{"デモ": {"例": "テスト"}} - 結果として得られた水和ストア:
{"デモ": {"foo": "bar", "例": "テスト"}}
二つのソースからのdemoプロパティの値は、ハイドレーションで結合されます。
マージを完全に無効にしたい場合は、hardSet リコンシリエーターを使用してください。これにより、ストアの状態がストレージエンジンの内容に置き換えられます。これはしばしば望ましくありません。なぜなら、マイグレーションがより複雑になるからです - もしあなたが状態に新しい初期プロパティを追加すると、ユーザーのセッションがハイドレートされるとすぐに既存のユーザーに対してはそのプロパティが未設定になります。
状態を移行する
移行に関して言えば、Redux Persist は永続化された状態を新しいバージョンにアップグレードするための組み込みサポートを持っています。時には、プロパティを新しい代替品と置き換えることがあります。既存のユーザーがアプリをリセットせずに使用し続けられることを確認する必要があります。
マイグレーションは、migrate設定キーを使用して構成されます。最も簡単な方法は、状態をパラメータとして受け取り、移行された状態を返す関数を渡すことです。また、Redux Persistがマイグレーションが必要な時期を識別できるようにするために、version設定キーも設定する必要があります。versionが変更されるたびに、マイグレーション関数が呼び出されます。
const persistConfig = {
key: "root",
storage,
version: 1,
migrate: (state) => ({...state, oldProp: undefined, newProp: "foobar"});
};
関数アプローチの代替として、各バージョンステップのために個別のマイグレーション関数を作成できるオブジェクトを渡すことができます。これをRedux Persistの設定に渡す前に、createMigrate()関数に渡す必要があります。
// other imports omitted
import {createMigrate} from "redux-persist";
const migrations = {
1: state => ({...state, extraProp: true}),
2: state => ({...state, extraProp: undefined, extraPropNew: true})
};
const persistConfig = {
key: "root",
storage,
version: 2,
migrate: createMigrate(migrations)
}
この例では、ストアをバージョン2として初期化しています。もし状態がユーザーのデバイス上で既にバージョン0として存在していた場合、両方のマイグレーションが実行されます。もしユーザーが現在バージョン1にいる場合、最後のマイグレーションだけが実行されます。
変換を適用する
最後に言及すべき点は、Redux Persistが「変換」関数の使用をサポートしていることです。これらは設定に追加され、保存または復元されるデータを操作することを可能にします。
ライブラリのドキュメントでは、使用できるいくつかの一般的な変換がリストされています。これにより、アプリケーションレベルのロジックを自分で実装することなく、自動的に永続化された状態を圧縮、暗号化、または期限切れにすることができます。
変換は、設定オブジェクト内の配列として指定されます。指定された順序で実行されます。
const persistStore = {
key: "root",
storage,
transforms: [MyTransformer]
};
独自のトランスフォーマーを書くには、createTransform()関数を使用します。これには2つの関数と構成オブジェクトが渡されます:
import {createTransform} from "redux-persist";
const MyTransformer = createTransform(
(inboundState, key) => ({...inboundState, b64: btoa(inboundState.b64)}),
(outboundState, key) => ({...outboundState, b64: atob(outboundState.b64)}),
{}
);
この例では、状態のb64プロパティをそのBase64エンコードされた値として保存します。データがストレージ(outboundState)に保存されると、値はエンコードされます。保存された状態がハイドレートされるとき(inboundState)、それはデコードされます。
構成オブジェクトは、リデューサー名のホワイトリストとブラックリストを定義するために使用できます。その後、トランスフォーマーは、その制約に一致するリデューサーでのみ使用されます。
結論
Redux Persistはシンプルなインターフェースを持つ強力なライブラリです。わずか数行のコードで、Reduxストアの自動永続性を設定できます。ユーザーと開発者の皆さんは、その便利さに感謝することでしょう。
