本記事の目的
- Redux の最低限を理解する
- Redux の導入ができるようになる
Redux とは
Redux(リダックス) とは、状態(State)を一元管理するための JavaScript ライブラリです。
コンポーネント間でデータを共有したり、アプリ全体で参照したいような状態を定義する際によく使われます。
Redux は Flux アーキテクチャ という、「状態の流れを一方向に限定しよう」という思想に基づいて設計されています。これにより、アプリケーションの状態を予測しやすく、デバッグやテストもしやすくなるという利点があります。
主に React と一緒に使われることが多いですが、React 専用ではなく、Vue や Angular、あるいは純粋な JavaScript でも利用可能です。
Redux Toolkit とは
Redux Toolkit とは、Redux をより使いやすくするために公式から提供されているライブラリです。
従来の Redux では初期設定などの記述が複雑になりがちでしたが、以下のような Redux Toolkit の機能を使うことで直感的かつ簡潔に記述できます。
-
configureStore
:Store の設定を簡単に行える -
createSlice
:Reducer と Action をまとめて定義できる
公式ドキュメントでも、Redux を使う場合は Redux Toolkit を利用することが推奨されています。本記事でも、Redux Toolkit を使用する前提で解説を進めていきます。
導入手順
Redux Toolkit を使って Store を定義し、アプリケーションで Redux を利用できるようにする手順を紹介します。
1. インストール
Redux Toolkit と、React Redux(React 専用の Redux)をインストールします。
npm install @reduxjs/toolkit react-redux
2. Slice (Reducer + Action) を作成する
Redux Toolkit によって提供されている createSlice
を使用して Reducer と Action をまとめて定義します。
-
name
:Slice の名前(Redux DevTools 上で識別するためにも使われます) -
initialState
:管理する状態(State)の初期値 -
reducers
:状態をどのように更新するかを定義する関数群。ここで定義した各関数が、そのまま対応する Action となります
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
value: 0,
};
export const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
3. Store を作成する
Redux Toolkit によって提供されている configureStore
を使用して、アプリ全体で使用する Store を定義します。
-
reducer
:( 2 )で作成した Slice の、reducer
を指定。複数の Slice がある場合はオブジェクトとしてまとめます
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./features/counterSlice";
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
4. Provider を設置する
Provider コンポーネントを使用して、作成した Store をアプリ全体で使用できる状態にします。
これによって、配下のコンポーネントで useSelector
や useDispatch
(後述)を使って Store にアクセスできるようになります。
-
store
:( 3 )で作成した Store を指定
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import { store } from "./store";
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
);
これで、Redux を使用する準備が整いました 👏✨
使用方法
定義した State を、コンポーネント内で参照および更新する方法を紹介します。
状態を参照する
useSelector
フックを使用することで、最新の State を参照できます。
以下の例では、counter
Slice の value
を取得しています。
import React from "react";
import { useSelector } from "react-redux";
import type { RootState } from "./store";
export function CounterValue() {
const count = useSelector((state: RootState) => state.counter.value);
return <p>Count: {count}</p>;
}
状態を更新する
useDispatch
フックを使うことで、事前に定義した Action を実行し、Reducer を通じて State を更新できます。
import React from "react";
import { useDispatch } from "react-redux";
import { increment, decrement } from "./features/counterSlice";
import type { AppDispatch } from "./store";
export function CounterButtons() {
const dispatch = useDispatch<AppDispatch>();
return (
<div>
<button onClick={() => dispatch(increment())}>+1</button>
<button onClick={() => dispatch(decrement())}>-1</button>
</div>
);
}
Dispatch によって、「何を、どうするか」を表す Action オブジェクトが Store を経由して Reducer に送信されます。Reducer は受け取った Action に応じて処理を行い、実際に State を更新しているというイメージです。