ホームページ >ウェブフロントエンド >jsチュートリアル >ReduxとMobxの選定例を詳しく解説
Redux と Mobx はどちらも現在人気のあるデータ フロー モデルであり、Redux の代わりに何を選択するかについてコミュニティは当然混乱しているようです。開発者はどのソリューションを選択すればよいかわかりません。この問題は Redux と Mobx に限定されません。選択肢があるときはいつでも、人々は問題を解決する最善の方法は何かということに興味を持ちます。私が今書いていることは、2 つの状態管理ライブラリ Redux と Mobx の間の混乱を解決することです。
ほとんどの記事では React を使用して Mobx と Redux の使用法を紹介しています。ただし、ほとんどの場合、React を Angular、Vue、またはその他のものに置き換えることができます。
2016 年の初めに、私は React + Redux を使用してかなり大規模なアプリケーションを作成しました。 Mobx が Redux の代替として使用できることを発見したとき、時間をかけてアプリケーションを Redux から Mobx にリファクタリングしました。非常に快適に使用できるようになりましたので、その使用方法を説明します。
この記事は何について話しますか?このような長い記事を読む予定がない場合 (TLDR: 長すぎるため、読んでいません (このリンクを表示するには、ご自身のはしごをご持参ください))、目次をご覧ください。ただし、さらに詳しく説明したいと思います。まず、状態管理ライブラリがどのような問題を解決してくれるのかを簡単に確認したいと思います。結局のところ、React を作成するときに setState() のみを使用するか、他の SPA フレームワークを作成するときに setState() および同様のメソッドを使用するだけでも、同じように行うことができます。次に、それらの類似点と相違点について簡単に説明します。 3 番目に、React エコシステムの初心者に React の状態管理を学ぶ方法を示します。注意: Mobx と Redux に入る前に、まず setState() を使用してください。最後に、既に Mobx または Redux を使用するアプリケーションをお持ちの場合は、これらの状態管理ライブラリの 1 つから別の状態管理ライブラリへリファクタリングする方法について、私の理解をさらに詳しく説明します。
目次
私たちが解決しようとしている問題は何ですか?
Mobx と Redux の違いは何ですか?
React 状態管理の学習曲線
別の状態管理ソリューションを試してみませんか?
最後の考察
私たちが解決しようとしている問題は何ですか?
誰もがアプリケーションで状態管理を使用したいと考えています。しかし、それは私たちにとってどのような問題を解決してくれるのでしょうか?小さなアプリケーションを起動するときに状態管理ライブラリを導入している人は多いでしょう。誰もが Mobx と Redux について話していますよね?ただし、ほとんどのアプリケーションは、最初は大規模な状態管理を必要としません。このような人々は、Mobx や Redux などのライブラリが解決しようとしている問題を経験できないため、これは危険ですらあります。
現在の状況は、コンポーネントを使用してフロントエンドアプリケーションを構築することです。コンポーネントには独自の内部状態があります。たとえば、React では、上記のローカル状態は this.state と setState() を使用して処理されます。しかし、ローカル状態の状態管理は、肥大化したアプリケーションではすぐに混乱する可能性があります:
あるコンポーネントは別のコンポーネントと状態を共有する必要がある
あるコンポーネントは別のコンポーネントの状態をある程度変更する必要がある
アプリケーションのステータスを推測することがますます困難になります。多くの状態オブジェクトがコンポーネント レベルで互いの状態を変更する、複雑なアプリケーションになります。ほとんどの場合、状態オブジェクトと状態の変更を何らかのコンポーネントにバインドする必要はありません。状態をプロモートすると、コンポーネント ツリーから状態を使用できるようになります。
したがって、解決策は、Mobx や Redux などの状態管理ライブラリを導入することです。どこかで状態を保存、変更、更新するためのツールを提供します。 1 か所から状態を取得し、1 か所から変更し、1 か所から更新を取得できます。これは単一のデータソースの原則に従います。これにより、状態値と状態の変更はコンポーネントから切り離されるため、推測が容易になります。
Redux や Mobx などの状態管理ライブラリには、通常、React で使用される React-redux や mobx-react などの付属ツールがあり、コンポーネントが状態を取得できるようになります。通常、これらのコンポーネントはコンテナ コンポーネント、より具体的には接続コンポーネントと呼ばれます。コンポーネントを接続コンポーネントにアップグレードする限り、コンポーネント階層内のどこでも状態を取得および変更できます。
Mobx と Redux の違いは何ですか?
Redux と Mobx の違いについて説明する前に、それらの類似点について話したいと思います。
両方のライブラリは、JavaScript アプリケーションの状態を管理するために使用されます。これらは React にバンドルする必要はなく、AngularJ や VueJ などの他のライブラリと一緒に使用することもできます。しかし、それらは React のアイデアと非常によく統合されています。
ステータス管理ソリューションのいずれかを選択すれば、それに縛られていると感じることはありません。いつでも別のソリューションに切り替えることができるからです。 Mobx から Redux、または Redux から Mobx に切り替えることができます。以下にその方法を示します。
Dan Abramov の Redux は、flux アーキテクチャから派生しています。 Flux とは異なり、Redux は状態を保存するために複数のストアではなく単一のストアを使用します。また、状態を変更するためにディスパッチャではなく純粋な関数を使用します。flux に詳しくなく、状態管理に慣れていない場合は、使用しないでください。この内容に騙されてください。
Redux は FP (関数型プログラミング) の原則の影響を受けています。 FP は JavaScript で使用できますが、多くの人は Java などのオブジェクト指向言語の経験があります。彼らは最初、関数型プログラミングの原則に適応するのに苦労します。これが、Mobx が初心者にとってより簡単である理由です。
Redux は FP を採用しているため、純粋な関数を使用します。入力を受け取って出力を返す純粋な関数であり、他の依存関係はありません。純粋関数は、同じ入力が与えられると常に同じ出力を持ち、副作用はありません。
(state, action) => newState
Redux の状態は不変です。元の状態を変更するのではなく、常に新しい状態を返す必要があります。オブジェクト参照に基づいて状態の変更や変更を実行しないでください。
// don't do this in Redux, because it mutates the array function addAuthor(state, action) { return state.authors.push(action.author); } // stay immutable and always return a new object function addAuthor(state, action) { return [ ...state.authors, action.author ]; }
最後に、Redux のイディオムでは、状態の形式がデータベースのように標準化されます。エンティティは ID によってのみ相互に参照します。これがベスト プラクティスです。誰もがこれを行うわけではありませんが、normalizr を使用して状態を正規化することもできます。正規化された状態により、フラットな状態を維持し、エンティティを単一のデータ ソースとして維持できます。
{ post: { id: 'a', authorId: 'b', ... }, author: { id: 'b', postIds: ['a', ...], ... } }
Michel Weststrate の Mobx は、オブジェクト指向プログラミングとリアクティブ プログラミングの影響を受けています。状態を監視可能なオブジェクトにラップするので、状態は Observable のすべての機能を備えます。状態データには通常のセッターとゲッターのみを含めることができますが、observable を使用すると、データが変更されたときに更新された値を取得できます。
Mobx の状態は可変であるため、状態を直接変更します:
function addAuthor(author) { this.authors.push(author); }
さらに、状態エンティティは、相互に関連するネストされたデータ構造を維持します。状態を標準化する必要はなく、代わりにネストしたままにしておきます。
{ post: { id: 'a', ... author: { id: 'b', ... } } }
単一ストアと複数ストア
Redux では、すべての状態をグローバル ストアに置きます。このストア オブジェクトは単一のデータ ソースです。一方、複数のリデューサーを使用すると、不変の状態を変更できます。
一方、Mobx は複数のストアを使用します。 Redux リデューサーと同様に、技術レベルまたはドメインで分割して征服することができます。ドメイン エンティティを別のストアに保存しながら、ビュー内の状態の制御を維持したい場合もあります。結局のところ、アプリケーションを適切に見せるために状態を構成するのです。
技術的に言えば、Redux では複数のストアを使用することもできます。 1 つのストアのみを使用することを強制する人はいません。 しかし、それは Redux の推奨される使用法ではありません。それはベストプラクティスに反するからです。 Redux では、単一のストアがリデューサー上のグローバル イベントを通じて更新に応答します。
使い方は?
Redux の使用方法を学ぶには、以下のコードに従う必要があります。まず、ユーザー配列をグローバル状態に追加します。オブジェクト スプレッド演算子を使用して新しいオブジェクトを返していることがわかります。 ES6 (当初は ES5、実際には ES6) の Object.assign() を使用して、不変オブジェクトを操作することもできます。
const initialState = { users: [ { name: 'Dan' }, { name: 'Michel' } ] }; // reducer function users(state = initialState, action) { switch (action.type) { case 'USER_ADD': return { ...state, users: [ ...state.users, action.user ] }; default: return state; } } // action { type: 'USER_ADD', user: user };
新しいユーザーをグローバル状態に追加するには、dispatch({ type: 'USER_ADD', user: user }); を使用する必要があります。
Mobx では、ストアは 1 つのサブ状態のみを管理します (Redux でサブ状態を管理するリデューサーと同様) が、状態を直接変更できます。
@observable を使用すると、状態の変化を観察できます。
class UserStore { @observable users = [ { name: 'Dan' }, { name: 'Michel' } ]; }
これで、ストア インスタンスのメソッド userStore.users.push(user); を呼び出すことができます。これはベスト プラクティスですが、アクションを使用して状態を変更する方がより明示的です。
class UserStore { @observable users = [ { name: 'Dan' }, { name: 'Michel' } ]; @action addUser = (user) => { this.users.push(user); } }
Mobx では、useStrict() を追加してアクションの使用を強制できます。これで、ストア インスタンスのメソッド userStore.addUser(user); を呼び出して状態を変更できるようになります。
Redux と Mobx で状態を更新する方法について説明しました。 Redux の状態は読み取り専用であり、状態を変更するには明示的なアクションのみが可能ですが、Mobx の状態は、アクションを使用せずに直接変更できます。明示的なアクションを使用するには useStrict( ) を使用します。
React 状態管理の学習曲線
React アプリケーションは、Redux と Mobx を広範囲に使用します。ただし、これらは独立した状態管理ライブラリであり、React 以外のどこでも使用できます。彼らの相互運用ライブラリを使用すると、React コンポーネントを簡単に接続できます。 Redux + Reactの場合はreact-redux、MobX + Reactの場合はmobx-reactです。これらが React コンポーネント ツリーでどのように使用されるかについては後ほど説明します。
最近のディスカッションでは、Redux の学習曲線について議論していました。これは通常、次のシナリオで発生します: 状態管理に Redux を使用したい React 初心者。ほとんどの人は、React と Redux は単独では習得に時間がかかり、この 2 つを組み合わせると手に負えなくなる可能性があると考えています。代替手段としては、初心者により適した Mobx があります。
然而,我会建议 React 的初学者一个学习状态管理的新方法。先学习React 组件内部的状态管理功能。在 React 应用,你首先会学到生命周期方法,而且你会用 setState() 和 this.state 解决本地的状态管理。我非常推荐上面的学习路径。不然你会在 React 的生态中迷失。在这条学习路径的最后,你会认识到组件内部管理状态难度越来越大。毕竟那是 The Road to learn React 书里如何教授 React 状态管理的方法。
现在我们重点讨论 Redux 和 Mobx 为我们解决了什么问题?它俩都提供了在组件外部管理应用状态的方法。state 与组件相互解耦,组件可以读取 state ,修改 state ,有新 state 时更新。这个 state 是单一数据源。
现在你需要选择其中一个状态管理库。这肯定是要第一时间解决的问题。此外,在开发过相当大的应用之后,你应该能很自如使用 React 。
初学者用 Redux 还是 Mobx ?
一旦你对 React 组件和它内部的状态管理熟悉了,你就能选择出一个状态管理库来解决你的问题。在我两个库都用过后,我想说 Mobx 更适合初学者。我们刚才已经看到 Mobx 只要更少的代码,甚至它可以用一些我们现在还不知道的魔法注解。
用 Mobx 你不需要熟悉函数式编程。像“不可变”之类的术语对你可能依然陌生。函数式编程是不断上升的范式,但对于大部分 JavaScript 开发者来说是新奇的。虽然它有清晰的趋势,但并非所有人都有函数式编程的背景,有面向对象背景的开发者可能会更加容易适应 Mobx 的原则。
注:Mobx 可以很好的在 React 内部组件状态管理中代替 setState,我还是建议继续使用 setState() 管理内部状态。但链接文章很清楚的说明了在 React 中用 Mobx 完成内部状态管理是很容易的。
规模持续增长的应用
在 Mobx 中你改变注解过的对象,组件就会更新。Mobx 比 Redux 使用了更多的内部魔法实现,因此在刚开始的时候只要更少的代码。有 Angular 背景的会觉得跟双向绑定很像。你在一个地方保存 state ,通过注解观察 state ,一旦 state 修改组件会自动的更新。
Mobx 允许直接在组件树上直接修改 state 。
// component <button onClick={() => store.users.push(user)} />
更好的方式是用 store 的 @action 。
// component <button onClick={() => store.addUser(user)} /> // store @action addUser = (user) => { this.users.push(user); }
用 actions 修改 state 更加明确。上面也提到过,有个小功能可以强制的使用 actions 修改 state 。
// root file import { useStrict } from 'mobx'; useStrict(true);
这样的话第一个例子中直接修改 store 中的 state 就不再起作用了。前面的例子展示了怎样拥抱 Mobx 的最佳实践。此外,一旦你只用 actions ,你就已经使用了 Redux 的约束。
在快速启动一个项目时,我会推荐使用 Mobx ,一旦应用开始变得越来越大,越来越多的人开发时,遵循最佳实践就很有意义,如使用明确的 actions 。这是拥抱 Redux 的约束:你永远不能直接修改 state ,只能使用 actions 。
迁移到 Redux
一旦应用开始变得越来越大,越来越多的人开发时,你应该考虑使用 Redux 。它本身强制使用明确的 actions 修改 state 。action 有 type 和 payload 参数,reducer 可以用来修改 state 。这样的话,一个团队里的开发人员可以很简单的推断 state 的修改。
// reducer (state, action) => newState
Redux 提供状态管理的整个架构,并有清晰的约束规则。这是 Redux 的成功故事。
另一个 Redux 的优势是在服务端使用。因为我们使用的是纯 JavaScript ,它可以在网络上传输 state 。序列化和反序列化一个 state 对象是直接可用的。当然 Mobx 也是一样可以的。
Mobx 是无主张的,但你可以通过 useStrict() 像 Redux 一样使用清晰的约束规则。这就是我为什么没说你不能在扩张的应用中使用 Mobx ,但 Redux 是有明确的使用方式的。而 Mobx 甚至在文档中说:“ Mobx 不会告诉你如何组织代码,哪里该存储 state 或 怎么处理事件。”所以开发团队首先要确定 state 的管理架构。
状态管理的学习曲线并不是很陡峭。我们总结下建议:React 初学者首先学习恰当的使用 setState() 和 this.state 。一段时间之后你将会意识到在 React 应用中仅仅使用 setState() 管理状态的问题。当你寻找解决方案时,你会在状态管理库 Mobx 或 Redux 的选择上犹豫。应该选哪个呢?由于 Mobx 是无主张的,使用上可以和 setState() 类似,我建议在小项目中尝试。一旦应用开始变得越来越大,越来越多的人开发时,你应该考虑在 Mobx 上实行更多的限制条件或尝试使用 Redux 。我使用两个库都很享受。即使你最后两个都没使用,了解到状态管理的另一种方式也是有意义的。
尝试另一个状态管理方案?
你可能已经使用了其中一个状态管理方案,但是想考虑另一个?你可以比较现实中的 Mobx 和 Redux 应用。我把所有的文件修改都提交到了一个Pull Request 。在这个 PR 里,项目从 Redux 重构成了 Mobx ,反之亦然,你可以自己实现。我不认为有必要和 Redux 或 Mobx 耦合,因为大部分的改变是和其他任何东西解耦的。
你主要需要将 Redux 的 Actions、Action Creator、 Action Types、Reducer、Global Store 替换成 Mobx 的 Stores 。另外将和 React 组件连接的接口 react-redux 换成 mobx-react 。presenter + container pattern 依然可以执行。你仅仅还要重构容器组件。在 Mobx 中可以使用 inject 获得 store 依赖。然后 store 可以传递 substate 和 actions 给组件。Mobx 的 observer 确保组件在 store 中 observable 的属性变化时更新。
import { observer, inject } from 'mobx-react'; ... const UserProfileContainer = inject( 'userStore' )(observer(({ id, userStore, }) => { return ( <UserProfile user={userStore.getUser(id)} onUpdateUser={userStore.updateUser} /> ); }));
Redux 的话,你使用 mapStateToProps 和 mapDispatchToProps 传递 substate 和 actions 给组件。
import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; ... function mapStateToProps(state, props) { const { id } = props; const user = state.users[id]; return { user, }; } function mapDispatchToProps(dispatch) { return { onUpdateUser: bindActionCreators(actions.updateUser, dispatch), }; } const UserProfileContainer = connect(mapStateToProps, mapDispatchToProps)(UserProfile);
这有一篇怎样将 Redux 重构为 Mobx指南。但就像我上面说过的,反过来一样也是可以的。一旦你选择了一个状态管理库,你会知道那并没有什么限制。它们基本上是和你的应用解耦的,所以是可以替换的。
最后思考
每当我看 Redux vs Mobx 争论下的评论时,总会有下面这条:“Redux 有太多的样板代码,你应该使用 Mobx,可以减少 xxx 行代码”。这条评论也许是对的,但没人考虑得失,Redux 比 Mobx 更多的样板代码,是因为特定的设计约束。它允许你推断应用状态即使应用规模很大。所以围绕 state 的仪式都是有原因的。
Redux 库非常小,大部分时间你都是在处理纯 JavaScript 对象和数组。它比 Mobx 更接近 vanilla JavaScript 。Mobx 通过包装对象和数组为可观察对象,从而隐藏了大部分的样板代码。它是建立在隐藏抽象之上的。感觉像是出现了魔法,但却很难理解其内在的机制。Redux 则可以简单通过纯 JavaScript 来推断。它使你的应用更简单的测试和调试。
另外,我们重新回到单页应用的最开始来考虑,一系列的单页应用框架和库面临着相同的状态管理问题,它最终被 flux 模式解决了。Redux 是这个模式的成功者。
Mobx 则又处在相反的方向。我们直接修改 state 而没有拥抱函数式编程的好处。对一些开发者来说,这让他们觉得像双向绑定。一段时间之后,由于没有引入类似 Redux 的状态管理库,他们可能又会陷入同样的问题。状态管理分散在各个组件,导致最后一团糟。
使用 Redux,你有一个既定的模式组织代码,而 Mobx 则无主张。但拥抱 Mobx 最佳实践会是明智的。 开发者需要知道如何组织状态管理从而更好的推断它。不然他们就会想要直接在组件中修改它。
两个库都非常棒。Redux 已经非常完善,Mobx 则逐渐成为一个有效的替代。
相关推荐:
以上がReduxとMobxの選定例を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。