エンタープライズアプリケーションに最適なReact状態管理ツール
公開: 2022-03-11エンタープライズレベルのReactアプリケーションの開発者は、一貫したエンドユーザーエクスペリエンスにとって状態管理がいかに重要であるかを知っています。
ただし、状態管理の影響を受けるのはユーザーだけではありません。 React開発者は状態を作成して維持します。 彼らは、状態管理が単純で、拡張可能で、アトミックであることを望んでいます。 Reactはフックを導入することでこの方向に進んでいます。
状態を多くのコンポーネント間で共有する必要がある場合、問題が発生する可能性があります。 エンジニアは、ニーズに合ったツールとライブラリを見つける必要がありますが、同時に、エンタープライズグレードのアプリに必要な高い基準を満たしています。
この記事では、最も人気のあるライブラリを分析および比較し、エンタープライズレベルのアプリケーションの状態管理に最も適切なライブラリを選択します。
組み込みのReact状態管理機能
Reactには、複数のコンポーネントにまたがるデータを提供するための優れたツールがあります。 Contextの主な目標は、プロップドリルを回避することです。 私たちの目標は、頻繁な更新、再設計、新機能の導入など、エンタープライズアプリケーションで発生する可能性のあるさまざまなシナリオで状態を管理するための使いやすいツールを入手することです。
これはすべてContextで理論的には実行可能ですが、セットアップ、サポート、および最適化に時間がかかるカスタムソリューションが必要になります。 Contextの唯一の利点は、サードパーティのライブラリに依存しないことですが、このアプローチを維持するための努力を上回ることはできません。
さらに、ReactチームメンバーのSebastian Markbageは、新しいContext APIは、高頻度の更新ではなく、テーマの更新や認証管理などの低頻度の更新用に構築および最適化されていると述べています。
既存の図書館を調べる
GitHubには数十の状態管理ツールがあります(たとえば、Redux、MobX、Akita、Recoil、Zustand)。 しかし、それらのそれぞれを考慮に入れることは、無限の研究と比較につながるでしょう。 そのため、人気、使用法、メンテナに基づいて、3つの主要な競合他社に選択を絞り込みました。
比較を明確にするために、次の品質属性を使用します。
- 使いやすさ
- 保守性
- パフォーマンス
- 妥当性
- スケーラビリティ(より大きな状態で同じパフォーマンスで動作します)
- 変更可能性
- 再利用性
- エコシステム(機能を拡張するためのさまざまなヘルパーツールがあります)
- コミュニティ(多くのユーザーがいて、彼らの質問はWeb上で回答されます)
- 移植性(React以外のライブラリ/フレームワークで使用できます)
戻ってきた
Reduxは、2015年に作成された状態コンテナです。次の理由で非常に人気がありました。
- それが発売されたとき、深刻な代替手段はありませんでした。
- それは状態と行動の間の分離を提供しました。
-
react-reduxマジックは簡単な状態接続を可能にしました。 - ライブラリの共同作成者は、高く評価されているFacebook開発者であり、ReactのコアチームメンバーであるDanAbramovです。
データが存在するグローバルストアがあります。 ストアを更新する必要があるときはいつでも、レデューサーに行くアクションをディスパッチします。 アクションタイプに応じて、レデューサーは不変の方法で状態を更新します。
ReactでReduxを使用するには、 react-reduxを介してコンポーネントをストアの更新にサブスクライブする必要があります。
ReduxAPIの例
他のツールと区別するコードベースのReduxの基本的な部分はスライスです。 これらには、アクションとレデューサーのすべてのロジックが含まれています。
CodeSandbox
// slices/counter.js import { createSlice } from "@reduxjs/toolkit"; export const slice = createSlice({ name: "counter", initialState: { value: 0 }, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; } } }); export const actions = slice.actions; export const reducer = slice.reducer; // store.js import { configureStore } from "@reduxjs/toolkit"; import { reducer as counterReducer } from "./slices/counter"; export default configureStore({ reducer: { counter: counterReducer } }); // index.js import React from 'react' import ReactDOM from 'react-dom' import { Provider } from 'react-redux' import App from './App' import store from './store' ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ) // App.js import React from "react"; import { useSelector, useDispatch } from "react-redux"; import { actions } from "./slices/counter"; const App = () => { const count = useSelector((state) => state.counter.value); const dispatch = useDispatch(); return ( <div> <div> <button onClick={() => dispatch(actions.increment())}>Increment</button> <span>{count}</span> <button onClick={() => dispatch(actions.decrement())}>Decrement</button> </div> </div> ); }; export default App;品質属性
- 使いやすさ。 公式ツールキットパッケージの導入により、Reduxは非常にシンプルになりました。 スライス(初期状態、レデューサー、およびアクションの組み合わせ)を作成し、それをストアに渡し、フックを介してコンポーネントでアクセスします。
- 保守性。 Reduxはシンプルです。 何かを強化または修復する方法を理解するために、深い知識は必要ありません。
- パフォーマンス。 Reduxの主なパフォーマンスインフルエンサーはソフトウェアエンジニアです。 Reduxは、多くのロジックがない単純なツールです。 状態の更新が遅い場合は、公式ガイドラインに従って高速化できます。
- 妥当性。 Reduxは純粋関数(アクションとレデューサー)で構成されているため、単体テストに最適です。 また、ストア、アクション、およびレデューサーが連携して機能する統合テストを作成するメカニズムも提供します。
- スケーラビリティ。 デフォルトでは、Reduxには1つのグローバル状態があるため、スケーリングが困難です。 ただし、モジュラーレデューサーとミドルウェアの作成を可能にするredux-dynamic-modulesライブラリがあります。
- 変更可能性。 Reduxのカスタマイズは、ミドルウェアをサポートしているため、簡単に行えます。
- 再利用性。 Reduxはフレームワークに依存しないため、再利用性に非常に優れています。
- エコシステム。 Reduxは、役立つアドオン、ライブラリ、ツールの巨大なエコシステムを提供します。
- コミュニティ。 私たちの比較で最も古い状態管理ライブラリであるReduxは、重要な知識ベースを持つ大規模なコミュニティを蓄積してきました。 Stack Overflowには、
reduxタグが付いた最大30,000(〜19,000の回答)の質問があります。 - パルス。 Reduxは定期的に更新および保守されます。
MobX
MobXは、GitHubに23,000個の星が付いたもう1つの比較的古いライブラリです。 Reduxとの違いは、OOPパラダイムに従い、オブザーバブルを使用していることです。 MobXはMichelWeststrateによって作成され、現在ボストンを拠点とするMendixの助けを借りてオープンソース愛好家のグループによって維持されています。
MobXでは、監視可能なストアであるコンストラクター内にmakeObservable呼び出しを使用してJavaScriptクラスを作成します(適切なローダーがある場合は、 @observableデコレーターを使用できます)。 次に、クラスのプロパティ(状態)とメソッド(アクションと計算値)を宣言します。 コンポーネントは、この監視可能なストアにサブスクライブして、状態、計算値、およびアクションにアクセスします。
MobXのもう1つの重要な機能は、可変性です。 副作用を回避したい場合に備えて、状態をサイレントに更新できます。
MobXAPIの例
MobXのユニークな機能は、すべての魔法を内部に隠して、ほぼ純粋なES6クラスを作成できることです。 ロジックへの集中を維持するために必要なライブラリ固有のコードは少なくて済みます。
CodeSandbox
// stores/counter.js import { makeAutoObservable } from "mobx"; class CounterStore { value = 0; constructor() { makeAutoObservable(this); } increment() { this.value += 1; } decrement() { this.value -= 1; } } export default CounterStore; // index.js import React from "react"; import ReactDOM from "react-dom"; import { Provider } from "mobx-react"; import App from "./App"; import CounterStore from "./stores/counter"; ReactDOM.render( <Provider counter={new CounterStore()}> <App /> </Provider>, document.getElementById("root") ); // App.js import React from "react"; import { inject, observer } from "mobx-react"; const App = inject((stores) => ({ counter: stores.counter }))( observer(({ counter }) => { return ( <div> <div> <button onClick={() => counter.increment()}>Increment</button> <span>{counter.value}</span> <button onClick={() => counter.decrement()}>Decrement</button> </div> </div> ); }) ); export default App;品質属性
- 使いやすさ。 監視可能なストアは、状態管理の単一のエントリポイントです。 変更する場所が1つしかないため、MobXの使用が簡単になります。
- 保守性。 それはかなりの欠点です。 RxJS APIの知識がないと、目的の結果を得ることができません。 資格の低いチームでMobXを使用すると、状態の不整合の問題が発生する可能性があります。
- パフォーマンス。 MobXは独立したストアで構成されており、必要なストアのみをサブスクライブできます。 とても効果的です。
- 妥当性。 監視可能なストアは、リアクティブ機能が内部に隠されたプレーンなJavaScriptオブジェクトです。 テストは他のJavaScriptクラスの場合と同じです。
- スケーラビリティ。 監視可能なストアは論理的に分割されます。 MobXのスケーリングに問題はありません。
- 変更可能性。 MobXを使用すると、動作を変更したカスタムオブザーバブルを作成できます。 さらに、リアクションと呼ばれる概念があります。 反応は自動副作用をモデル化します。 これらのことにより、MobXは非常にカスタマイズ可能になります。
- 再利用性。 MobXはフレームワークにとらわれないため、再利用性に非常に優れています。
- エコシステム。 MobXで利用できる拡張機能は何百もあります。
- コミュニティ。 MobXには熱心なファンがたくさんいます。 Stack Overflowの
mobxタグには約1,600(約1,000の回答)の質問があります。 - パルス。 MobXは定期的に更新および保守されます。
反動
Recoilは比較的新参者であり、Reactチームの最新の発案者です。 その背後にある基本的な考え方は、共有状態や派生データなどの欠落しているReact機能の単純な実装です。

なぜ実験的なライブラリがエンタープライズレベルのプロジェクトのためにレビューされるのか疑問に思われるかもしれません。 まず第一に、Recoilは現在Reactコミュニティで最も議論されているトピックの1つです。 第二に、RecoilはFacebookに支えられており、すでにいくつかのアプリケーションで使用されています。つまり、ある時点で安定したバージョンになるでしょう。 最後に、これはReactで状態を共有するためのまったく新しいアプローチであり、Recoilが廃止されたとしても、同じパスをたどる別のツールがあると確信しています。
リコイルは、アトムとセレクターの2つの用語の上に構築されています。 アトムは共有状態のピースです。 コンポーネントは、アトムをサブスクライブしてその値を取得/設定できます。
画像でわかるように、値が変更されると、サブスクライブされたコンポーネントのみが再レンダリングされます。 それはリコイルを非常に高性能にします。
Recoilが箱から出してすぐに使えるもう1つの素晴らしい点は、セレクターです。 セレクターは、アトムまたは他のセレクターから集約された値です。 消費者にとって、アトムとセレクターの間に違いはありません。彼らはいくつかの反応部分をサブスクライブしてそれを使用する必要があります。
アトム/セレクターが変更されるたびに、それを使用する(つまり、サブスクライブされる)セレクターが再評価されます。
リコイルAPIの例
Recoilのコードは、競合他社とははるかに異なります。 これはReactフックに基づいており、この状態の変更よりも状態構造に重点を置いています。
CodeSandbox
// atoms/counter.js import { atom } from "recoil"; const counterAtom = atom({ key: "counter", default: 0 }); export default counterAtom; // index.js import React from "react"; import ReactDOM from "react-dom"; import { RecoilRoot } from "recoil"; import App from "./App"; ReactDOM.render( <RecoilRoot> <App /> </RecoilRoot>, document.getElementById("root") ); // App.js import React from "react"; import { useRecoilState } from "recoil"; import counterAtom from "./atoms/counter"; const App = () => { const [count, setCount] = useRecoilState(counterAtom); return ( <div> <div> <button onClick={() => setCount(count + 1)}>Increment</button> <span>{count}</span> <button onClick={() => setCount(count - 1)}>Decrement</button> </div> </div> ); }; export default App;品質属性
- 使いやすさ。 Recoilは、Reactの
useStateのように機能するため、最も使いやすいツールの1つです。 - 保守性。 Recoilで行う必要があるのは、コンポーネント内のセレクターとフックを維持することだけです。より多くの価値があり、ボイラープレートが少なくなります。
- パフォーマンス。 RecoilはReactの外部に状態ツリーを構築します。 状態ツリーを使用すると、ツリー全体の変更ではなく、必要なものを取得して聞くことができます。 また、内部で十分に最適化されています。
- 妥当性。 Recoilは、そのアトムとセレクターをテストするためのメカニズムを提供します。
- スケーラビリティ。 複数の独立した部分に分割される状態は、スケーラビリティの優れたプレーヤーになります。
- 変更可能性。 Recoilは、値とその集計の保存のみを担当します。 データフローがないため、簡単にカスタマイズできます。
- 再利用性。 RecoilはReactに依存しています。 他の場所で再利用することはできません。
- エコシステム。 現在、リコイルのエコシステムはありません。
- コミュニティ。 リコイルは新鮮すぎて大きなコミュニティを持つことができません。 StackOverflowの
recoiljsタグには約70の質問があります。 - パルス。 リコイルはめったに更新されません(最新の2つの更新の間に6か月が経過しました)。 また、GitHubには多くの未解決の問題があります。
適切なReact状態管理ツールの選択
エンタープライズグレードのアプリに関して、これらのReactグローバル状態管理ライブラリはどのように積み重ねられますか?
リコイルは若くて新鮮ですが、現時点ではコミュニティもエコシステムもありません。 Facebookはそれに取り組んでおり、APIは有望に見えますが、巨大なReactアプリケーションは、コミュニティのサポートが弱いライブラリに依存することはできません。 さらに、これは実験的なものであり、さらに危険です。 今日のReactエンタープライズアプリケーションには間違いなく良いオプションではありませんが、注意を払う価値があります。
MobXとReduxはこれらの問題を共有しておらず、市場に出回っているほとんどの大手企業がこれらの問題を使用しています。 それらが互いに異なるのは、学習曲線です。 MobXには、リアクティブプログラミングの基本的な理解が必要です。 プロジェクトに関与するエンジニアが十分なスキルを持っていない場合、アプリケーションはコードの不整合、パフォーマンスの問題、および開発時間の増加につながる可能性があります。 MobXは受け入れ可能であり、チームが反応性を認識している場合はニーズを満たします。
Reduxにもいくつかの問題があり、主にスケーラビリティとパフォーマンスに関するものです。 ただし、MobXとは異なり、これらの問題に対する実証済みのソリューションがあります。
すべての長所と短所を考慮し、私の個人的な経験を考慮すると、Reactエンタープライズレベルのアプリケーションに最適なオプションとしてReduxをお勧めします。
