坂本研のゼミ室

Redux Persistでデータを永続化する

はじめに

React Reduxを使ってみる - BLOGで、クリック数をカウントするアプリを作りました。
しかし、ページを再読み込みするとカウントが0に戻ってしまっていたので
Redux Persistを使ってデータを永続化してみます。

Redux Persist

Reduxのストアのデータをローカルストレージに保存する。

※ローカルストレージ
HTMLでサポートされている、Webローカル環境に値を保存する機能
それぞれの値にキーをつけて保存し、いつでもキーを使って値を取得できる。

インストール

npm install --save redux-persist

Redux Persistを実装する

Redux Persistでは、通常のReducerとstoreに永続化のための
機能を組み込んだpersistReducerとpersistorを作成する。
f:id:TakaShinoda:20191002174949p:plain

  • メッセージとカウントを表示する
  • クリック時はカウントを+1して"INCREMENT"と表示する
  • shuft+クリックでカウントを0にリセットして"RESET"と表示する

index.js

import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import { PersistGate } from "redux-persist/integration/react";
import App from "./components/App";

// ステートの値
let state_value = {
  counter: 0,
  message: "COUNTER"
};

// レデューサー
function countReducer(state = state_value, action) {
  switch (action.type) {
    case "INCREMENT":
      return {
        counter: state.counter + 1,
        message: "INCREMENT"
      };
    case "RESET":
      return {
        counter: 0,
        message: "RESET"
      };
    default:
      return state;
  }
}

// Redux Persistの設定
const config = {
  key: "root",
  storage: storage
};

// パーシストレデューサーの作成
const persistedReducer = persistReducer(config, countReducer);

// ストア、パーシスターの作成
let store = createStore(persistedReducer);
let persistor = persistStore(store);

// 表示をレンダリング
ReactDOM.render(
  <Provider store={store}>
    <PersistGate loading={<p>now loading...</p>} persistor={persistor}>
      <App />
    </PersistGate>
  </Provider>,
  document.getElementById("root")
);
使用オブジェクトのインポート
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import { PersistGate } from "redux-persist/integration/react";
Redux Persistの設定

Redux Persistの設定情報を値として用意する。
key : 任意の文字列。データ保存用の識別キー
storage : データ保存先の種類

const config = {
  key: "root",
  storage: storage
};
persistReducerの作成

引数に先ほど設定した値と使用するReducerを指定して
persistReducerを作成する。

const persistedReducer = persistReducer(config, countReducer);
store, persistorの作成

まず通常のstoreをpersistedReducerを引数にして作成し
それを元にpersistStoreでpersistorを作成する。

let store = createStore(persistedReducer);
let persistor = persistStore(store);
PersistGate

データの読み書きが完了してからコンポーネント類を表示するように調整
表示するコンポーネントをラップして使用する。
Reduxを使う場合のProviderコンポーネントの中にPersistGateを用意する
loading : 値のローディング中の表示
persistor : 作成したpersistorを指定する

ReactDOM.render(
  <Provider store={store}>
    <PersistGate loading={<p>now loading...</p>} persistor={persistor}>
      <App />
    </PersistGate>
  </Provider>,
  document.getElementById("root")
);

App.js

import React from "react";
import { connect } from "react-redux";
import Message from "./Message";
import Button from "./Button";

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>Redux Persist</h1>
        <Message />
        <Button />
      </div>
    );
  }
}

export default connect()(App);

Message.js

import React from "react";
import { connect } from "react-redux";

class Message extends React.Component {
  render() {
    return (
      <p>
        {this.props.message}: {this.props.counter}
      </p>
    );
  }
}

export default connect(state => state)(Message);

Button.js

import React from "react";
import { connect } from "react-redux";

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.doAction = this.doAction.bind(this);
  }

  doAction(e) {
    if (e.shiftKey) {
      this.props.dispatch({ type: "RESET" });
    } else {
      this.props.dispatch({ type: "INCREMENT" });
    }
  }

  render() {
    return (
      <button onClick={this.doAction}>
        click
      </button>
    );
  }
}

export default connect()(Button);