Redux Toolkit を使った Redux 活用法
Redux Toolkit を使うと Redux の設定が簡素化されます。この連載では、何回かに分けて Redux Toolkit を使った Redux の活用事例を紹介していきます。
Redux Toolkit を利用する利点
React などで Redux を利用する際のハードルになるのは、Redux を利用する為の細かい設定が初心者には面倒という点がありました。Vue などでよく利用される、Vuex や Pinia などの場合は、Redux に比べると設定の部分が大幅に簡素化されていて、初心者でも扱いやすいというのが大きな利点になっています。
Redux Toolkit を利用すると、この設定の部分を大きく簡素化する事ができます。
Redux Toolkit をする場合に必要な設定は:
* ストアの作成
* React への組み込み
* Slice Reducer の作成とストアへの登録
この三点です。
ストア(store)は、データを一括管理するための、Redux の仕組みと考えてください。 このストアには、後から説明する、「slice reducer」と呼ばれる、実際に一括管理するデータの定義と、そのデータの処理方法を記述するモジュールを登録する必要がありますが、最初はまずその「型」を作ります。「slice reducer」は作成後に追加で登録すれば OK です。
その後で、作成したストア(store)を React に組み込んで、あとは、実際のデータとその処理方法を記述した、「slice reducer」を作成して、最初に作成したストア(store)に登録します。
Redux Toolkit を利用しない場合には、「Slice Reducer」の部分に相当する部分でさらに細かい設定が必要になります。Reducer とは別に、必要になる「アクション(action)」と呼ばれる、データ処理を予め決めた上で、Reducer を作成する必要があります。React Toolkit を利用すると、これを一つの「Slice Reducer」で済ませる事ができるので簡単です。
さらに、データの更新する際に、特に配列(array)や JSON などのデータの「中身」を更新する際には、元のデータのコピーを作成してから、配列や JSON 全体を置き換えるような処理が必要でしたが、こうした処理も、Redux Toolkit が裏方で処理をやってくれるので、特別な設定が不要になります。同様に、非同期で処理されたデータを扱う場合にも、「thunk」などのミドルウエアを導入する必要がありましたが、Redux Toolkit を使うとそうした操作も、裏方で処理してくれるので、改めてモジュールをインストールして設定する必要がないので設定自体はかなり簡単になります。
Redux Toolkit 公式サイトに詳しい情報が解説されています。
Redux Toolkit を利用するには?
Redux を React で利用するには、React で Redux を利用する為のモジュール「react-redux」を利用するのが一般的です。これに加えて従来は、Redux の基本モジュール「redux」を合わせて利用していました。
Redux Toolkit を利用する場合には、この基本モジュールの代わりに「@reduxjs/toolkit」というモジュールを利用します。つまり、以下の二つのモジュールをインストールすれば Redux Toolkit を利用できます。
* @reduxjs/toolkit
* react-redux
インストールは、プロジェクトフォルダで以下のコマンドを実行します。 (*)npmを利用する例です。
$ npm install @reduxjs/toolkit react-redux
必要なパッケージをインストールしたら、まずは「_Redux store_」を作成します。 一括管理している、データの操作には「_Reducer_」と呼ばれる「仕組み」が必要です。
まずは、「_reducer_」の部分は空欄で作成しておきます。後から「slice reducer」を作成した段階で、ここに記述を追加して登録するようになります。
import { configureStore } from "@reduxjs/toolkit";
export const store: any = configureStore({
reducer: {},
});
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;
// Infer type: {sample: SampleReducer, ....}
export type AppDispatch = typeof store.dispatch;
今回は、Typescript ベースで型の情報もエキスポートしておきます。Javascript で実装する場合には不要です。
ストア(Store) を作成したら、React に組み込みます。 これは、一括管理するデータの情報(store)を React で指定するための処理です。 Vite でプロジェクトを作成した場合には、「src/main.tsx」を変更します。
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "react-redux";
import { store } from "./redux/store";
import App from "./App";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
これで、Redux を利用する為の基本的な準備ができました。 あとは、「slice reducer」を作成してストア(store)に登録します。
Slice reducer の作成
実際に、一括管理するデータの定義と処理方法は、「slice reducer」で記述するわけですが、ここでは簡単な例として、シンプルにカウンターの値を一括管理するような例で紹介します。
今回一括管理するのは、「_SimpleState_」の「_value_」という値だけです。 この値に対する操作は、
* 「1」づつ値を増やす(_increment_)
* カウンターの値を「0」に戻す(_clear_)
の2種類です。
import { createSlice } from "@reduxjs/toolkit";
interface SampelState {
value: number;
}
const initialState: SampelState = {
value: 0,
};
export const sampleSlice = createSlice({
name: "counter",
initialState,
reducers: {
clear: (state) => {
state.value = 0;
},
increment: (state) => {
state.value += 1;
},
},
});
export const { clear, increment } = sampleSlice.actions;
export default sampleSlice.reducer;
基本は、一括管理するデータの定義、この例では「_SampleState_」という形で、「_value_」を定義しています。データの型が決まったら、後は初期値の設定をします。この例では「0」を最初に設定しています。
最後が、データの処理の記述でこの例では、「_clear()_」と「_increment()_」の二つの処理を実装しています。一つは、「1づつ加算する処理」もう一つは、「カウンタをクリアする処理」です。
あとは、データを利用する表示の「部品」からこの処理を呼び出すと、一括管理しているデータを操作できるようになります。
この「slice reducer」を最初に作成したストア(store)に登録します。 空になっている「reducer」に以下のように追加します。
export const store: any = configureStore({
reducer: {
sample: SampleReducer,
},
});
実際の表示の部品からデータを使う
実際に、今回作成した Redux を表示の「部品」から実装する例です。
ボタンを二つ用意して、一つのボタンを押すとカウントアップして、もう一つのボタンを押すとカウンターを「0」にリセットするような表示になっています。
import React from "react";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "../redux/store";
import { clear, increment } from "../redux/reducers/sampleReducer";
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
import "./styles/redux1.css";
export default function Redux1() {
const count = useAppSelector((state: RootState) => state.sample.value);
const dispatch = useAppDispatch();
return (
<React.Fragment>
<div>
<button
className="btn btn-primary"
onClick={() => dispatch(increment())}
>
{"count:" + count}
</button>
<button className="btn btn-secondary" onClick={() => dispatch(clear())}>
Clear
</button>
</div>
</React.Fragment>
);
}
一括管理しているデータを参照する場合(読み出す場合)には、「_useSelector_」をこの表示の部品用に拡張した、「_useAppSelector()_」を利用します。データの操作も同様に、「_useAppDispatch()_」を使って、「slice reducer」で記述した処理を呼び出します。
これで、一つのボタンには、現在のカウンタの値を表示して、クリックされる度に1づつカウントアップして、もう一つのボタンを押すとカウンタを「0」に戻すような機能が実現できます。
まとめ
今回は、Redux Toolkit を利用した Redux の活用事例でシンプルな例を紹介してみました。 Redux Toolkit を利用すると、少なくても最初の設定は若干シンプルになります。
これくらいのシンプルな例では、Redux Toolkit の便利な点を全て利用するというわけにはいきませんが、それでも、Vue でよく利用される Vuex や Pinia に近い感覚で利用できる利点は大きいと思います。
React でも Redux が手軽に利用できるようになると、利用のハードルもかなり下がります。今まで苦手意識が強かった方も、Redux Toolkit を使うと実装がかなりシンプルになります。まずは簡単な事例から試してみると将来の実装の選択肢も広がります!