このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →
Reduxの歴史(簡略版)
2011年: JS MVCフレームワーク
AngularJS、Ember、Backboneなどの初期のJavaScript MVCフレームワークには課題がありました。AngularJSは「コントローラー」とテンプレートの分離を試みましたが、テンプレート内で<div onClick="$ctrl.some.deeply.nested.field = 123">のような記述を防ぐ仕組みはありませんでした。一方、Backboneはイベントエミッターを基盤としており、Model、Collection、Viewのすべてがイベントを発行可能でした。例えばModelが"change:firstName"イベントを発行し、Viewがこれを購読する構成です。しかし、_あらゆる_コードがこれらのイベントを購読して追加ロジックを実行でき、それが_さらに多くの_イベントを引き起こす可能性がありました。
この構造はデバッグやメンテナンスを非常に困難にしました。1つのモデルのフィールドを更新するだけで数十のイベントが発生し、アプリ全体にロジックが波及する可能性があります。また、任意のテンプレートがいつでも状態を変更できるため、状態更新時の挙動を予測することが不可能でした。
2014年: Flux
2012-2013年頃、Reactが初めて公開された時点で、Facebookは社内で数年使用していました。彼らが直面した問題の一つは、「未読通知の数」のように、複数の独立したUIパーツが同じデータにアクセスする必要がある場合の処理でした。Backboneスタイルのコードでは、このロジックを適切に管理することが困難でした。
Facebookは最終的に「Flux」というパターンを考案しました:PostsStoreやCommentsStoreのような複数のシングルトンStoreを作成します。各StoreインスタンスはDispatcherに登録され、Storeの更新をトリガーする_唯一の_方法はDispatcher.dispatch({type: "somethingHappened"})を呼び出すことでした。このプレーンオブジェクトは「アクション」と呼ばれます。このアイデアは、状態更新ロジックを半集中化するものでした。アプリの任意の部分が状態を突然変更することはできず、すべての状態更新が予測可能になるというものです。
Facebookは2014年頃にこの「Fluxアーキテクチャ」の概念を発表しましたが、パターンを完全に実装したライブラリは提供しませんでした。これによりReactコミュニティは、このパターンをベースにした_数十種類もの_Fluxインスパイアードライブラリを開発しました。
2015年: Reduxの誕生
2015年半ば、Dan AbramovはReduxという新たなFluxインスパイアードライブラリの開発を開始しました。カンファレンス講演で「タイムトラベルデバッグ」を実演するのが目的でした。このライブラリはFluxパターンを採用しながらも、関数型プログラミングの原則を適用していました。Storeの_インスタンス_ではなく、不変更新を行う予測可能なreducer関数を使用します。これにより、時間を前後して移動し、様々な時点での状態を確認できるようになります。またコードをより直感的で、テスト可能で、理解しやすいものにしました。
Reduxは2015年にリリースされ、他のFluxインスパイアードライブラリを駆逐しました。Reactエコシステムの上級開発者に早期に採用され、2016年には「Reactを使うならReduxも_必ず_使うべきだ」という主張が広まりました(率直に言えば、これが_必要ない_場面でもReduxを使う人が大量に発生する結果を招きました!)。
また当時、Reactには_レガシー_なContext APIしか存在せず、これは基本的に機能不全状態でした:更新された値を正しく下流に渡せませんでした。Contextにイベントエミッターを配置して購読することは可能でしたが、プレーンなデータ伝達には不向きでした。このため、Reduxがアプリケーション全体で一貫して更新値を伝達できる手段として多くの人々に採用され始めたのです。
ダンは初期段階で「Reduxはコードを書く最短の方法ではなく、予測可能性と理解しやすさを目的としている」と述べていました。これは一貫したパターンを持つこと(状態更新はリデューサーが行うため、状態値の可能性・可能なアクション・発生する更新を常にリデューサーロジックで確認できる)と、ロジックをコンポーネントツリー外に移動すること(UIは主に「このイベントが発生した」と通知し、コンポーネントを簡素化する)に関連しています。さらに、リデューサーやセレクターのような「純粋関数」で書かれたコードは引数入力→結果出力というシンプルな構造で理解しやすくなります。最後に、Reduxの設計はRedux DevToolsを可能にし、ディスパッチされた全アクションの可読性のあるリスト、アクション/状態の内容、各アクションによる変更を表示します。
初期のReduxパターンは特に定型コードが多くなりがちでした。単一のアクションタイプ(const ADD_TODO = "ADD_TODO")、アクションクリエーター関数、リデューサーケースを定義するためだけに、actions/todos.js、reducers/todos.js、constants/todos.jsを用意するのが一般的でした。また、スプレッド演算子を使ったイミュータブルな更新を手動で記述する必要があり、これはエラーを起こしやすい作業でした。人々はReduxでサーバー状態の取得とキャッシュを行いましたが、取得用のサンク作成、取得データを使ったアクションディスパッチ、リデューサー内でのキャッシュ状態管理には大量の手書きコードが必要でした。
Reduxはこうした定型コードにもかかわらず人気を博しましたが、これは常に最大の懸念点でした。
2017年: エコシステムの競合
2017-18年までに状況は変化しました。コミュニティの焦点は「クライアントサイド状態管理」から「データ取得とキャッシュ」に移行し、Apollo、React Query、SWR、Urqlといったデータ取得ライブラリが台頭しました。同時に、コンポーネントツリーを通じて更新値を適切に伝播する_新しい_React Context APIが登場しました。
これにより、Reduxは以前ほど「必須」ではなくなりました。同じ問題を解決する代替ツールが登場し、重複範囲は様々ながら(多くの場合より少ないコードで)機能を提供しました。「定型コード」への頻繁な不満も、Redux利用者に大きな懸念を引き起こしました。
2019年: Redux Toolkit
そこで2019年、私たちはより少ないコードで同等のReduxロジックを記述する簡易方法としてRedux Toolkitを開発・リリースしました。RTKも依然「Redux」です(単一ストア、イミュータブル更新ロジックによるリデューサー内での状態更新をトリガーするアクションディスパッチ)が、よりシンプルなAPIと優れた組み込みのデフォルト動作を備えています。これにはReact QueryとApolloに触発された組み込みデータ取得・キャッシュライブラリのRTK Queryも含まれます。
現在、RTKはReduxロジックを記述する標準的な方法です。あらゆるツールと同様にトレードオフがあります。RTKはZustandより若干コード量が多くなる可能性がありますが、アプリロジックとUIを分離する有用なパターンを提供します。Reduxはすべてのアプリに適したツールではありませんが、Reactアプリで最も広く使われる状態管理ライブラリであり、優れたドキュメントを備え、一貫性と予測可能性のある構造でアプリを構築する多くの機能を提供します。
参考情報
-
Reduxの考古学と設計ノート (初期の設計ディスカッションやプロジェクト設計目標の説明へのリンクを含む)