🍑

Redux Toolkit と RTK Query: 基本概要

2024/07/15に公開

Redux Toolkit と RTK Query は、Reduxでのデータ管理とAPI通信をより効率的かつシンプルにするツールで、開発者はReduxのボイラープレートや複雑性を気にすることなく、ビジネスロジックに集中できる。

データのローディング、成功、失敗の状態を簡単に扱えるほか、自動的なキャッシング、データの再利用、ポーリングなどの高度な機能もサポートしている。

JavaScriptフレームワークとの組み合わせが可能で、Reactだけでなく、AngularやVue.jsなど他のフレームワークとも相性が良い。

Note: この記事「Redux Toolkit スライスの基本: 初期状態、リデューサー、extraReducers の使い方」では、具体的なスライスの実装例について詳しく解説。

1. configureStore(ストアの設定)

この機能により、ミドルウェアの設定、リデューサーの組み込み、およびデバッグツールの活用が可能になる。

import { configureStore } from '@reduxjs/toolkit';
import countersReducer from './features/counters/countersSlice';

const store = configureStore({
  reducer: { // リデューサーを組み込む
    // 以下の「counters」はグローバルステートとなる
    counters: countersReducer,
  },
  // ミドルウェアの設定(アクションがリデューサーに到達する前に実行される関数)
  middleware: (getDefaultMiddleware) => getDefaultMiddleware(),
  devTools: true // デバッグツールの活用
});

export default store;

2. createReducer(カスタムリデューサーの作成)

通常、データを安全に更新するためには、元のデータを直接変更せず新しいデータを作成して置き換える必要がある。createReducerは、データを直接変更しているように見えるが、内部的にImmerライブラリが実装されており、自動的に新しいデータを安全な方法で生成する。これにより、コードはより直感的で読みやすくなる。

import { createReducer } from '@reduxjs/toolkit';

const initialState = { count: 0 };

const counterReducer = createReducer(initialState, {
  increment: (state) => {
    // Immerにより、ここでstateのcountを直接増やしても、元のデータは変更されない
    state.count += 1;
  },
  decrement: (state) => {
    // Immerにより、ここでstateのcountを直接増やしても、元のデータは変更されない
    state.count -= 1;
  }
});

export default counterReducer;

createReducer: カスタムなロジックや複雑な状態管理に適している。

3. createSlice(グローバルステートの管理)

createSliceは、アプリケーションの特定のデータセグメント(スライス)を管理するためのツール。この関数を使用すると、リデューサー、アクションクリエーター、アクションタイプを一箇所で定義でき、状態管理のコードをより簡潔で効率的に書くことが可能。

import { createSlice } from '@reduxjs/toolkit';

// カウンタースライスの定義
const counterSlice = createSlice({
  name: 'counter', // スライスの名前
  initialState: { value: 0 }, // 初期状態
  reducers: {
    //以下の「increment」「decrement」「incrementByAmount」がアクションクリエーター
    increment: state => { state.value += 1; },
    decrement: state => { state.value -= 1; },
    incrementByAmount: (state, action) => { state.value += action.payload; }
  }
});
// 生成されたアクションクリエーターをエクスポート
export const { increment, decrement, incrementByAmount } = counterSlice.actions;

// リデューサーをエクスポート
export default counterSlice.reducer;

createSlice: 基本的な状態管理やシンプルなリデューサーに適している。

4. createEntityAdapter(スライス使用時に管理をしやすくする)

createEntityAdapterを使うことによって、各データの基本単位であるエンティティコレクション(ここではカウンターエンティティコレクション)の管理が効率的かつ強力になる。このツールを利用することで、状態を正規化し、セレクタを自動的に生成でき、結果としてアプリケーションのパフォーマンスと保守性が向上する。以下は、カウンターエンティティの管理例。

import { createSlice, createEntityAdapter } from '@reduxjs/toolkit';

// エンティティアダプターの作成
const countersAdapter = createEntityAdapter();

// 初期状態の設定
const initialState = countersAdapter.getInitialState();

// createSliceの定義
const countersSlice = createSlice({
  name: 'counters',
  initialState,
  reducers: {
    addCounter: countersAdapter.addOne,
    updateCounter: countersAdapter.updateOne,
    removeCounter: countersAdapter.removeOne,
  },
});

// アクションクリエーターのエクスポート
export const { addCounter, updateCounter, removeCounter } = countersSlice.actions;

// セレクタの自動生成
export const {
  selectAll: selectAllCounters,
  selectById: selectCounterById,
  selectIds: selectCounterIds,
} = countersAdapter.getSelectors((state) => state.counters);

// リデューサーのエクスポート
export default countersSlice.reducer;

createEntityAdapter: createSliceを使うとき、複雑なエンティティコレクションの管理に適している。

5. RTK Query(APIの管理)

RTK Queryは、Redux Toolkitに含まれるデータフェッチングおよびキャッシングのプロセスを簡略化するためのツール。APIコールを行い、データを自動的にキャッシュし、状態を管理する。これにより、開発者はAPIリクエストの状態管理やデータの同期に関する多くのボイラープレートコードを書く必要がなくなる。RTK Queryは、createApi関数を使用して設定されるAPI sliceを通じて、エンドポイントごとにクエリやミューテーションを定義できる。これにより、データの取得、キャッシング、ポーリング、リアルタイム更新などを簡単に行うことができる。

Note: この記事「RTK Queryの活用: フックを使う場合と関数を使う場合の実装例」では、具体的な実装例について詳しく解説している。

スライスとRTK Queryのディスパッチの違い

Redux ToolkitとRTK Queryには、それぞれ異なるディスパッチの方法が存在する。

1. スライスのディスパッチ
状態の直接的な更新: スライスをディスパッチすると、リデューサーが実行されて状態が即座に更新される。UIの状態を直接変更するために使用される。

2. RTK Queryのディスパッチ
APIコール + 状態の更新: RTK Queryでは、ディスパッチによってAPIリクエストが実行され、その結果に基づいて状態が更新される。リクエストの進行状況も自動で管理される。これにより、状態管理とAPI操作の両方を効率的に行える。

具体的な実装例については、以下の記事にあり。

Discussion