データを永続化したい理由
ブラウザをリロードするとグローバルStateが初期化されたくないとき。
バックエンドを使う場合はセッションを使うけど、フロントエンドだけで実現したいときはローカルストレージに保存する。
ローカルストレージに直接データを保存することもできるけど、Reduxを使う場合はredux-persist
を使うのが良い。
redux-persistのインストール
npm install redux-persist
storeの定義
import { configureStore } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; // ローカルストレージを使用
import userSlice from './userSlice'; // ユーザーデータを管理するスライス
const persistConfig = {
key: 'root', // ストレージに保存するキー
storage,
};
const persistedReducer = persistReducer(persistConfig, userSlice.reducer);
const store = configureStore({
reducer: {
user: persistedReducer,
},
});
const persistor = persistStore(store);
export { store, persistor };
Reduxプロバイダーを設定
redux-persistのPersistGate
を使用して、ストアの再初期化が完了するまでUIを保留する。
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root')
);
useSliceの作成
ここは普通のSlice作成
import { createSlice } from '@reduxjs/toolkit';
const userSlice = createSlice({
name: 'user',
initialState: {
userId: null,
},
reducers: {
setUserId: (state, action) => {
state.userId = action.payload;
},
clearUserId: (state) => {
state.userId = null;
},
},
});
export const { setUserId, clearUserId } = userSlice.actions;
export default userSlice;
redux-persistとRedux-toolkitを一緒に使うと発生する可能性があるエラー
A non-serializable value was detected in an actionエラー
和訳するとアクションでシリアル化できない値が検出されました
であり、Reduxでシリアライズ不可なデータを使おうとするために発生するエラー
シリアライズ化とは
データ構造やオブジェクトを保存や送信が可能な形式(通常は文字列形式)に変換すること。
シリアライズ化できるデータ
- プリミティブ型
- オブジェクト
- 配列
シリアライズ化できないデータ
- 関数
- 特殊なオブジェクト(Promise、Symbol、Map、Set)
- クラスインスタンス
Reduxは関数やクラスインスタンス(シリアライズ不可データ)を使えないが、redux-persistはシリアライズ不可データをつかえる
Reduxはシリアライズ可能なデータのみを扱う設計になっているので、プリミティブ型やオブジェクト配列しか使えない。一方で、redux-persistはシリアライズ不可なデータ(関数やクラスインスタンス)も使える。
対応方法:Redux-toolkitのシリアライズデータチェックを除外する
Redux-toolkitのconfigureStore
で格納するデータがシリアライズできるかどうかをチェックしており、その設定をミドルウェアで制御できる。
redux-persist由来のアクションはシリアライズできるかどうかのチェックを除外する。
const persistedReducer = persistReducer(persistConfig, userReducer);
const store = configureStore({
reducer: {
flow: flowReducer,
layout: layoutReducer,
respondent: respondentReducer,
user: persistedReducer,
// user: userReducer,
},
+ middleware: (getDefaultMiddleware) =>
+ getDefaultMiddleware({
+ serializableCheck: {
+ // 非シリアライズ可能な値を無視するための例外を指定
+ ignoredActions: [
+ "persist/PERSIST",
+ ],
+ },
}),
});