メインコンテンツにスキップ

Redux Toolkit が今日の Redux の使用方法である理由

Redux Toolkit とは?

Redux Toolkit (略して "RTK") は、Redux ロジックを記述するための公式推奨アプローチです。 @reduxjs/toolkit パッケージはコアの redux パッケージをラップし、Redux アプリケーションの構築に不可欠と思われる API メソッドと共通の依存関係を含んでいます。Redux Toolkit は、推奨されるベストプラクティスを組み込み、ほとんどの Redux タスクを簡素化し、一般的なミスを防ぎ、Redux アプリケーションの記述を容易にします。

今日、あらゆる Redux ロジックを書いているなら、必ず Redux Toolkit を使ってそのコードを書くべきです!

RTK には、ストアのセットアップReducer の作成と不変の更新ロジックの記述、さらには状態の "スライス" 全体を一度に作成するなど、多くの一般的なユースケースを簡素化するユーティリティが含まれています。

Redux を初めて使用するユーザーでも、既存のアプリケーションを簡素化したい経験豊富なユーザーでも、Redux Toolkit は Redux コードの改善に役立ちます。

ヒント

Redux Toolkit を使用した「最新の Redux」の使用方法については、以下のページをご覧ください。

Redux Toolkit と Redux コアの違い

「Redux」とは?

最初に、「Redux とは何か?」という質問があります。

Redux とは、実際には

  • 「グローバル」状態を含む単一のストア
  • アプリケーションで何かが発生したときに、プレーンオブジェクトアクションをストアにディスパッチする
  • それらのアクションを見て、不変に更新された状態を返す純粋な Reducer 関数

必須ではありませんが、Redux コードには通常、以下も含まれます

  • それらのアクションオブジェクトを生成するアクションクリエイター
  • 副作用を有効にするミドルウェア
  • 副作用のある同期または非同期ロジックを含む Thunk 関数
  • ID でアイテムを検索できるようにするための正規化された状態
  • 派生データを最適化するための、Reselect ライブラリを使用したメモ化セレクター関数
  • アクション履歴と状態の変更を表示するための Redux DevTools 拡張機能
  • アクション、状態、その他の関数の TypeScript タイプ

さらに、Redux は通常、React コンポーネントが Redux ストアと通信できるようにするために React-Redux ライブラリと一緒に使用されます。

Redux コアは何をするのか?

Redux コアは非常に小さく、意図的に意見のないライブラリです。いくつかの小さな API プリミティブを提供します

  • Redux ストアを実際に作成するための createStore
  • 複数のスライス Reducer を 1 つの大きな Reducer に結合するための combineReducers
  • 複数のミドルウェアをストアエンハンサーに結合するための applyMiddleware
  • 複数のストアエンハンサーを 1 つのストアエンハンサーに結合するための compose

それ以外は、アプリケーションの他のすべての Redux 関連ロジックは、すべて自分で記述する必要があります。

良いニュースは、これは Redux が多くの異なる方法で使用できることを意味します。悪いニュースは、コードの記述を容易にするヘルパーがないことです。

たとえば、Reducer 関数は単なる関数です。Redux Toolkit より前は、通常、switch ステートメントと手動更新を使用して Reducer を記述していました。また、おそらく手書きのアクションクリエイターとアクションタイプの定数も一緒に持っていたでしょう

レガシーの手書き Redux の使用
const ADD_TODO = 'ADD_TODO'
const TODO_TOGGLED = 'TODO_TOGGLED'

export const addTodo = (text) => ({
type: ADD_TODO,
payload: { text, id: nanoid() },
})

export const todoToggled = (id) => ({
type: TODO_TOGGLED,
payload: { id },
})

export const todosReducer = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
return state.concat({
id: action.payload.id,
text: action.payload.text,
completed: false,
})
case TODO_TOGGLED:
return state.map((todo) => {
if (todo.id !== action.payload.id) return todo

return {
...todo,
completed: !todo.completed,
}
})
default:
return state
}
}

このコードは、特に redux コアライブラリの API に依存していません。しかし、これは書くべきコードがたくさんあります.不変の更新には、手書きのオブジェクトスプレッドと配列操作がたくさん必要であり、その過程で誤って状態を変化させてしまうミスを犯しやすかったです (常に Redux バグの第一の原因です!)。また、厳密には必須ではありませんが、1 つの機能のコードを actions/todos.jsconstants/todos.jsreducers/todos.js などの複数のファイルに分散させるのが一般的でした。

さらに、ストアのセットアップには通常、Thunk などのよく使用されるミドルウェアを追加し、Redux DevTools Extension のサポートを有効にするための一連の手順が必要でした。これらはほとんどすべての Redux アプリケーションで使用される標準ツールであるにもかかわらずです。

Redux Toolkit は何をするのか?

これらは Redux ドキュメントで最初に示されたパターンでしたが、残念ながら非常に冗長で反復的なコードがたくさん必要です。このボイラープレートのほとんどは、Redux を使用するのに必ずしも必要ありません。その上、ボイラープレートコードはミスをする機会を増やしました.

Redux Toolkit は、手書きの Redux ロジックから「ボイラープレート」を排除し、一般的なミスを防ぎ、標準の Redux タスクを簡素化する API を提供するために作成されました.

Redux Toolkit は、すべての Redux アプリケーションで最も一般的な操作を簡素化する 2 つの主要な API から始まります

  • configureStore は、Reducer の結合、Thunk ミドルウェアの追加、Redux DevTools 統合のセットアップなど、1 回の関数呼び出しで適切に構成された Redux ストアをセットアップします。また、名前付きオプションパラメータを受け取るため、createStore よりも構成が簡単です.
  • createSlice を使用すると、Immer ライブラリを使用して、スプレッドを必要とせずに state.value = 123 のような「ミューテート」JS 構文を使用して不変の更新を記述できる Reducer を記述できます。また、各 Reducer のアクションクリエイター関数を自動的に生成し、Reducer の名前に基づいて内部的にアクションタイプの文字列を生成します。最後に、TypeScript でうまく機能します.

つまり、あなたが書くコードは劇的に簡素化できます。たとえば、同じ todos Reducer は次のようになります

features/todos/todosSlice.js
import { createSlice } from '@reduxjs/toolkit'

const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
todoAdded(state, action) {
state.push({
id: action.payload.id,
text: action.payload.text,
completed: false,
})
},
todoToggled(state, action) {
const todo = state.find((todo) => todo.id === action.payload)
todo.completed = !todo.completed
},
},
})

export const { todoAdded, todoToggled } = todosSlice.actions
export default todosSlice.reducer

すべてのアクションクリエイターとアクションタイプは自動的に生成され、Reducer コードは短く、理解しやすくなっています。また、それぞれの場合に実際に何が更新されているかがより明確になります.

configureStore を使用すると、ストアのセットアップは次のように簡素化できます

app/store.js
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from '../features/todos/todosSlice'
import filtersReducer from '../features/filters/filtersSlice'

export const store = configureStore({
reducer: {
todos: todosReducer,
filters: filtersReducer,
},
})

この 1 つの configureStore 呼び出しは、手動で行っていた通常のセットアップ作業をすべて自動的に行います

  • スライス Reducer は自動的に combineReducers() に渡されました
  • redux-thunk ミドルウェアが自動的に追加されました
  • 偶発的な突然変異をキャッチするために、開発モードのミドルウェアが追加されました
  • Redux DevTools Extension が自動的にセットアップされました
  • ミドルウェアと DevTools エンハンサーがまとめて構成され、ストアに追加されました

同時に、configureStore は、ユーザーがこれらのデフォルトの動作を変更できるオプションを提供します (Thunk をオフにして Saga を追加したり、本番環境で DevTools を無効にするなど)。

そこから、Redux Toolkit には一般的な Redux タスクのための他の API が含まれています

  • createAsyncThunk: 標準の「非同期リクエストの前後に行動をディスパッチする」パターンを抽象化します
  • createEntityAdapter: 正規化された状態での CRUD 操作のための事前構築された Reducer とセレクター
  • createSelector: メモ化セレクターのための標準 Reselect API の再エクスポート
  • createListenerMiddleware: ディスパッチされたアクションに応じてロジックを実行するための副作用ミドルウェア

最後に、RTK パッケージには、Redux アプリケーション向けの完全なデータフェッチおよびキャッシュソリューションである「RTK Query」も、個別のオプションの `@reduxjs/toolkit/query` エントリポイントとして含まれています。エンドポイント (REST、GraphQL、または任意の非同期関数) を定義し、データのフェッチ、ロード状態の更新、結果のキャッシュを完全に管理する Reducer とミドルウェアを生成できます。また、`const { data, isFetching} = useGetPokemonQuery('pikachu')` のように、コンポーネントでデータを取得するために使用できる React フックも自動的に生成します

これらの各 API は完全にオプションであり、特定のユースケース向けに設計されており、アプリケーションで実際に使用する API を選択できます。ただし、これらのタスクを支援するために、すべてを強くお勧めします.

Redux Toolkit は依然として「Redux」です! 更新のためのディスパッチされたアクションオブジェクトと状態を不変に更新する Reducer、非同期ロジックのために Thunk を記述する機能、正規化された状態を管理する機能、TypeScript でコードを記述する機能、DevTools を使用する機能が依然としてあります。同じ結果を得るためにあなたが書くコードがはるかに少なくなりました!

Redux Toolkit を使用してほしい理由

Redux のメンテナーとしての私たちの意見は

ヒント

すべての Redux ユーザーに Redux Toolkit を使用して Redux コードを記述してほしいと考えています。コードが簡素化されるだけでなく、多くの一般的な Redux のミスやバグが解消されるからです!

初期の Redux パターンの「ボイラープレート」と複雑さは、Redux の必要な部分ではありませんでした。これらのパターンが存在したのは、以下の理由のみです

  • 元の「Flux アーキテクチャ」では、同じアプローチのいくつかが使用されていました
  • 初期のReduxドキュメントでは、コードをタイプ別に異なるファイルに分割できるように、アクションタイプの定数などが示されていました。
  • JavaScriptはデフォルトで mutable な言語であり、immutable な更新を行うには、手動でオブジェクトのスプレッドや配列の更新を行う必要がありました。
  • Reduxは、わずか数週間で構築され、意図的に少数のAPIプリミティブのみで設計されました。

さらに、Reduxコミュニティは、ボイラープレートを追加する特定のアプローチを採用してきました。

  • 副作用を記述するための一般的なアプローチとして、redux-sagaミドルウェアの使用を重視しています。
  • ReduxアクションオブジェクトのTS型を手書きし、ユニオン型を作成して、型レベルでディスパッチできるアクションを制限することを推奨しています。

長年にわたり、私たちはReduxが実際にどのように使われているのかを見てきました。コミュニティが、アクションタイプやクリエーターの生成、非同期ロジックと副作用、データフェッチなどのタスクのために、何百ものアドオンライブラリを記述してきたのを見てきました。また、状態の誤った変更、単純な状態更新を行うためだけに数十行のコードを記述する必要があること、コードベースがどのように連携しているかを追跡するのが難しいなど、ユーザーにとって常に苦痛の原因となってきた問題も見てきました。私たちは、Reduxを学習して使用しようとして、すべての要素がどのように組み合わされているかを理解するのに苦労し、概念の数と記述しなければならない追加コードの量に混乱している何千人ものユーザーを支援してきました。私たちは、ユーザーがどのような問題に直面しているかを*知っています*。

私たちは、Redux Toolkitをこれらの問題を解決するために特別に設計しました!

  • Redux Toolkitは、ストアの設定を単一の明確な関数呼び出しに簡素化しますが、必要に応じてストアのオプションを完全に設定する機能を保持しています。
  • Redux Toolkitは、Reduxのバグの第一の原因となってきた、偶発的な状態変更を排除します。
  • Redux Toolkitを使用すると、アクションクリエーターやアクションタイプを手書きする必要がなくなります。
  • Redux Toolkitを使用すると、手動でエラーが発生しやすいimmutableな更新ロジックを記述する必要がなくなります。
  • Redux Toolkitを使用すると、Redux機能のコードを複数のファイルに分散させるのではなく、1つのファイルに簡単に記述できます。
  • Redux Toolkitは、優れた型安全性を提供し、コードで定義する必要のある型の数を最小限に抑えるように設計されたAPIを備えた、優れたTSサポートを提供します。
  • RTK Queryを使用すると、データのフェッチと読み込み状態の追跡を管理するためのthunk、reducer、アクションクリエーター、またはeffect hookを*一切*記述する必要がなくなります。

このため

ヒント

私たちは、ユーザーがRedux Toolkit(@reduxjs/toolkitパッケージ)を使用*すべき*であり、今日では新しいReduxコードにはレガシーのreduxコアパッケージを使用*すべきではない*ことを特に推奨しています!

既存のアプリケーションの場合でも、少なくともcreateStoreconfigureStoreに切り替えることをお勧めします。開発モードのミドルウェアは、既存のコードベースにおける偶発的な状態変更やシリアライズ可能性のエラーを検出するのにも役立ちます。また、最もよく使用しているreducer(および今後記述するreducer)をcreateSliceに切り替えることをお勧めします。コードはより短く、理解しやすくなり、安全性の向上により、時間と労力を節約できます。

**reduxコアパッケージは引き続き機能しますが、現在では廃止されていると考えています**。そのすべてのAPIは@reduxjs/toolkitからも再エクスポートされており、configureStorecreateStoreが行うすべてのことを行いますが、デフォルトの動作と設定可能性が向上しています。

Redux Toolkitが何をしているかをよりよく理解するために、低レベルの概念を理解することは*役に立ちます*。そのため、"Redux Fundamentals"チュートリアルでは、抽象化なしでReduxの仕組みを説明しています。*しかし*、これらの例は学習ツールとしてのみ示されており、Redux Toolkitが従来の手書きのReduxコードをどのように簡素化するかを示して終了します。

reduxコアパッケージを単独で使用している場合、コードは引き続き機能します。**しかし、@reduxjs/toolkitに切り替え、Redux Toolkit APIを使用するようにコードを更新することを強くお勧めします!**

詳細情報

詳細については、これらのドキュメントページとブログ投稿を参照してください。