React での開発において、コンポーネントをまたいだ状態管理は一つの大きなテーマです。「Redux」はその代表的な解決策ですが、従来の方法は記述量が多く、複雑な設定(いわゆるボイラープレート)が必要で、挫折してしまった方も多いのではないでしょうか。
そんな悩みを解決するために登場したのが Redux Toolkit (RTK) です。Redux をよりシンプルに、そして効率的に使えるように設計されており、現在では Redux の公式推奨ライブラリとなっています。
この記事では、Redux Toolkit を使った状態管理の基本的な流れを、できるだけシンプルなカウンターアプリを例に解説します。
Redux Toolkit の導入
まずは、プロジェクトに必要なパッケージをインストールします。React プロジェクトのルートディレクトリで、以下のコマンドを実行してください。
@reduxjs/toolkit
が Redux Toolkit 本体、react-redux
が React と Redux を連携させるためのライブラリです。
npm の場合
npm install @reduxjs/toolkit react-redux
yarn の場合
yarn add @reduxjs/toolkit react-redux
ストアの作成
次に、アプリケーション全体の状態を保持する「ストア」を作成します。Redux Toolkit ではconfigureStore
という関数を使うことで、非常に簡単にストアをセットアップできます。
src
ディレクトリにapp
フォルダとfeatures
フォルダを作成しましょう。このように機能をfeatures
に、ストア設定をapp
に分けるのは、公式で推奨されている構成です。
src/app/store.js
import { configureStore } from "@reduxjs/toolkit"; import counterReducer from "../features/counter/counterSlice"; export const store = configureStore({ reducer: { counter: counterReducer, }, });
configureStore
は、Redux DevTools 拡張機能との連携などを自動で行ってくれるため、これだけで基本的なストアの設定は完了です。reducer
オブジェクトの中に、後述する「Slice」からエクスポートした Reducer を登録していきます。
Redux Toolkit の Slice(スライス)の作成
Slice(スライス)は、Redux Toolkit の核心的な機能です。アプリケーションの状態を機能ごとに分割して管理するための仕組みで、従来バラバラに記述していたActions、Action Types、Reducers のすべてを一つのファイルにまとめることができます。
src
ディレクトリのfeatures/counter
フォルダ内にcounterSlice.js
を設置します。
src/features/counter/counterSlice.js
import { createSlice } from "@reduxjs/toolkit"; const initialState = { value: 0, }; export const counterSlice = createSlice({ name: "counter", initialState, reducers: { increment: (state) => { // Redux ToolkitはImmerライブラリを使用しているため、 // stateを直接変更するようなロジックを記述できる state.value += 1; }, decrement: (state) => { state.value -= 1; }, }, }); // 各コンポーネントで使えるようにActionをエクスポート export const { increment, decrement } = counterSlice.actions; // storeで使えるようにreducerをエクスポート export default counterSlice.reducer;
createSlice
は、name
(スライスの名前)、initialState
(初期状態)、reducers
(状態を更新するロジック)の 3 つを設定します。
注目すべきは、state.value += 1
のように、まるで状態を直接変更しているかのように書ける点です。これは内部で Immer というライブラリが働いており、実際には安全なイミュータブル(不変的)な更新が行われるため、安心して記述できます。
React-Redux の Provider 設定
作成したストアを React アプリケーション全体で利用できるように、Provider
コンポーネントでアプリケーションのルートとなるApp
コンポーネントをラップします。
src/main.jsx (または src/index.js
)
import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import { store } from "./app/store"; import { Provider } from "react-redux"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode> );
src/App.jsx
import React from "react"; import { Counter } from "./features/counter/Counter"; import "./App.css"; // スタイルはお好みで function App() { return ( <div className="App"> <header className="App-header"> <Counter /> </header> </div> ); } export default App;
このようにApp
コンポーネントを挟むことで、より実際のアプリケーションに近い構造になります。これで、App
以下のすべての子コンポーネントから Redux ストアにアクセスできるようになりました。
Redux Hooks の実装
最後に、React コンポーネントからストアの値を参照したり、値を更新するための Action を呼び出したりします。これにはuseSelector
とuseDispatch
という 2 つのフックを使用します。
src/features/counter/Counter.jsx
import React from "react"; import { useSelector, useDispatch } from "react-redux"; import { decrement, increment } from "./counterSlice"; export function Counter() { // ストアの状態からcounter.valueの値を取得 const count = useSelector((state) => state.counter.value); // Actionを呼び出すためのdispatch関数を取得 const dispatch = useDispatch(); return ( <div> <div> <button aria-label="Increment value" onClick={() => dispatch(increment())}> + </button> <span>{count}</span> <button aria-label="Decrement value" onClick={() => dispatch(decrement())}> - </button> </div> </div> ); }
useSelector
: ストアの状態(state)を引数に取り、そこから必要な値を抽出するためのフックです。useDispatch
: Action をdispatch
(発行)するための関数を返します。
💡 パフォーマンスのヒント
useSelector
は、返した値が変更されるたびにコンポーネントを再レンダリングします。不要な再レンダリングを防ぐため、state.counter
のようにオブジェクト全体を返すのではなく、 state.counter.value
のようにコンポーネントで使う最小限の値だけを返す ように心がけましょう。
まとめ
Redux Toolkit を使うことで、かつての Redux が抱えていた多くの課題が解決されていることがお分かりいただけたかと思います。
configureStore
でストアのセットアップが劇的に簡素化createSlice
で Actions、Reducers、Constants が一つにまとまり、記述量が大幅に削減- Immerの統合により、安全性を保ちつつ直感的なロジックの記述が可能に
Redux Toolkit は、もはや Redux を使う上での「選択肢」ではなく「スタンダード」です。ぜひこの機会にマスターして、快適な React 開発に役立ててください。🚀