🌏

ReduxToolkitのstateを永続化する

2022/06/09に公開

ReduxToolkitの値を永続化したい(๑╹ω╹๑ )

小難しく言うてますが、端的に言うとリロードしても消えないようにしたいということです。

reduxtoolkit-永続化.gif

( +ボタンを押した後、リロードしても数字がリセットされません )

すばらしいですね。
これができれば、サーバサイドから取得した値を再リロード後、いちいちもう一回サーバサイドへ取得しに行く必要がなくなります。

では、Let's ハンズオン!!

環境構築

今回のスキルスタックは以下になります。

  1. React
  2. TypeScript
  3. ReduxToolkit

とにかくシンプルです。

では、以下のコマンドを実行しましょう!

create-react-app localstorage-redux --template redux-typescript

このコマンドを実行して、HappyHacking!!と祈ってもらえれば作業開始です。

では、完了したら以下コマンドでアプリを開始させてください。

npm start

こんな画面になりましたか?

スクリーンショット 2022-06-09 22.06.46.png

では、コードを見ていきましょう。

実装

まずは、Store内のReduxのstateを永続化するためのライブラリをインストールしましょう!
今回はredux-persistというライブラリを使用します。

npm install redux-persist

次にsrc/app/store.tsを追記していきます。

こんな感じにしてみてください。

src/app/store.ts
import { Action, configureStore, ThunkAction } from '@reduxjs/toolkit';
import { combineReducers } from "redux";
import { persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import thunk from 'redux-thunk';
import counterReducer from '../features/counter/counterSlice';

const reducers = combineReducers({
 counter: counterReducer,
});

const persistConfig = {
    key: 'root',
    storage
};

const persistedReducer = persistReducer(persistConfig, reducers);

const store = configureStore({
    reducer: persistedReducer,
    middleware: [thunk]
});

export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>;

export default store;

そして、src/index.tsxがエラーでてると思うので、改修。
React18で書いておきますね。

src/index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
import { PersistGate } from 'redux-persist/integration/react';
import App from './App';
import store from './app/store';
import './index.css';
import reportWebVitals from './reportWebVitals';

let persistor = persistStore(store);

const container = document.getElementById('root')!;
const root = createRoot(container);

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

そして、src/features/counter/Counter.tsxの不要箇所を削除

src/features/counter/Counter.tsx
import React, { useState } from 'react';
import { useAppDispatch, useAppSelector } from '../../app/hooks';
import styles from './Counter.module.css';
import {
  decrement,
  increment,
  incrementByAmount,
  selectCount,
} from './counterSlice';

export function Counter() {
  const count = useAppSelector(selectCount);
  const dispatch = useAppDispatch();
  const [incrementAmount, setIncrementAmount] = useState('2');

  const incrementValue = Number(incrementAmount) || 0;

  return (
    <div>
      <div className={styles.row}>
        <button
          className={styles.button}
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          -
        </button>
        <span className={styles.value}>{count}</span>
        <button
          className={styles.button}
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          +
        </button>
      </div>
      <div className={styles.row}>
        <input
          className={styles.textbox}
          aria-label="Set increment amount"
          value={incrementAmount}
          onChange={(e) => setIncrementAmount(e.target.value)}
        />
        <button
          className={styles.button}
          onClick={() => dispatch(incrementByAmount(incrementValue))}
        >
          Add Amount
        </button>
      </div>
    </div>
  );
}

これで、再度npm startしてみるとこんな画面になります。

スクリーンショット 2022-06-09 22.17.08.png

プラスボタンを連打してみてください。

スクリーンショット 2022-06-09 22.18.36.png

そして、ブラウザを再リロード!

スクリーンショット 2022-06-09 22.19.05.png

5 がめでたくそのまま残りましたね。

これでReduxToolkitのstate永続化が完了です!

お疲れ様でした。

Discussion