ReduxToolkitのstateを永続化する

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


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

![reduxtoolkit-永続化.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/61e9e9d9-c961-55b6-7097-211a151a14b4.gif)


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

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

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

# 環境構築

今回のスキルスタックは以下になります。
1. React
2. TypeScript
3. ReduxToolkit

とにかくシンプルです。
コードの全貌はこちらに置いておきます。

https://github.com/SatakeYusuke19920527/localstorage-redux

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

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

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

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

```bash
npm start
```

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

![スクリーンショット 2022-06-09 22.06.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/1a4f8113-b847-0539-15cf-61e5d5d2c588.png)

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

# 実装

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

```bash
npm install redux-persist
```

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

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

```typescript: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で書いておきますね。

```typescript: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の不要箇所を削除
```typescript: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/c2949f67-3440-9609-7741-03996b4c49d8.png)

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

![スクリーンショット 2022-06-09 22.18.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/3ab87602-d20f-9c35-a222-3a97276ac8f9.png)

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

![スクリーンショット 2022-06-09 22.19.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/ce9a9502-a424-4077-dc6f-74953733d9c8.png)

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

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


お疲れ様でした。