以前説明したimmutableJSは簡単にimmutableオブジェクトを扱うことができるのでreduxのreducerで大活躍します。
normalizr風味のreducerを作る場合は、下記のようにimmutableJSのMapとListで簡潔に書く事ができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import { ADD_THOUGHT } from "../actions/thought"; import { Map, fromJS } from "immutable"; const initialState = fromJS({ ids: [], entities: {} }); export default function thought(state = initialState, action) { switch (action.type) { case ADD_THOUGHT: return state .setIn(["entities", action.draft.tid], action.draft) .set("ids", state.get("ids").push(action.draft.tid)); default: return state; } } |
一つ問題があります。immutableJSはfromJS
を利用するとMapオブジェクトでstateを保存します。これが、redux-persist
を使うとMapで保存できないという問題です。redux-persist
はtransformsという機構でserialize, deserializeを行うことができ、ここにモジュールを適用することで保存できるようになります。redux-persistのauthorであるr2tzz氏が提供するredux-persist-immutableがありますが、READMEの情報が少なくよくわかりません。他のソースを読むと、トップレベルでMapの置換を適用するようです。私の今回のreducerではnavというReact Navigatorのreducerがあるので、ここに適用する必要はないと思っていました。
Redux Persist Transform Immutable
Redux Persist Transform Immutableというものもr2tzz氏が提供しています。これは、reducerごとにシリアライズ・デシリアライズをできるものです。これはREADMEもしっかり書いてあります:)
では、実際のコードを見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import immutableTransform from "redux-persist-transform-immutable"; ... componentWillMount() { persistStore( this.store, { storage: AsyncStorage, transforms: [ immutableTransform({ whitelist: ["user", "draft", "thought"], blacklist: ["nav"] }) ] }, async () => { await this.store.dispatch(initUser()); await this._loadAsync(); } ); //.purge(); } |
使い方は、transformsのvalueにimmutableTransformを入れます。whitelist/blacklistで追加します。どちらかを指定すれば片方がいらないかもしれませんが、わかりやすくするためにwhitelist/blacklist両方いれています。React Nativeでの利用なので、storage: AsyncStorage
はそのままです。 ちなみにpersistStore(..).perge()でstateを消去できるので、開発初期にはよく使うことになると思います。