森です。
課題
redux-persist を使っていて、ブラウザリロード時にブラウザストレージからストアにデータを復旧する前に render されるのを防ぎたい。ストアに値があることが前提のコンポーネントでエラーになるから。公式ドキュメントとしてレシピがあった(Delay Render Until Rehydration Complete) が、これだと、すべてのステートがローカルストレージに保存されてしまいます。
前提
- redux-persist で、すべてではないいくつかのステートをローカルストレージとセッションストレージに保存しています
- ステートは { loadingFlag: true, data: { foo: ‘bar’ }} といった構造で、data 以下だけをブラウザストレージに保存します
- UniversalJS を意識した設計になっており、プロバイダを提供するコンポーネントが、ネイティブアプリ(Cordova)版 と ブラウザ版で別にあります
解決案
公式ドキュメントのレシピは、persistStore するときのオプション指定が行われていないことが、今回の私たちの状況にとって問題です。rehydrated か否かを redux のストア common.rehydratedFlag として、プロバイダを render するコンポーネントをコンテナにして、それを参照すれば済むのではないかというのが、最初の案でした。しかし、connect するときに store がないといったエラーになり、うまくゆきませんでした。
redux-persist の persistStore では第三引数で、処理終了時のコールバックを指定できます。そこで、ここで rehydrate の終了イベントを emit して、プロバイダコンポーネントでリスンして、プロバイダコンポーネントのステートとして用意した rehydratedFlag を true にする、という対応をとりました。これでプロバイダコンポーネントが Cordova アプリ、ブラウザアプリと複数ある場合も、それなりに DRY なまま、望んだ結果を表現できました。
実装の概略は以下の通りです。