本文由Michel Weststrate和Aaron Boyer同行评审。感谢所有SitePoint的同行评审员,使SitePoint的内容尽善尽美!
如果您曾经使用jQuery编写过比非常简单的应用程序更复杂的应用程序,您可能遇到过保持UI不同部分同步的问题。通常,数据的更改需要反映在多个位置,并且随着应用程序的增长,您可能会发现自己陷入困境。为了控制这种混乱,通常使用事件来让应用程序的不同部分知道何时发生了更改。
那么,您今天是如何管理应用程序状态的呢?我要冒昧地说,您过度订阅了更改。没错。我什至不认识你,但我就要指出来。如果您没有过度订阅,那么我敢肯定您工作太努力了。
当然,除非您使用MobX……
关键要点
- 利用MobX简化状态管理:利用MobX通过可观察对象有效地管理应用程序状态,减少在Redux等其他状态管理库中发现的复杂性和样板代码。
-
MobX自动更新:实现MobX的
autorun
功能,以自动响应状态更改更新UI组件,无需手动事件处理,从而简化整个应用程序的同步过程。 - 使用计算值增强性能:使用MobX的计算值从状态派生数据,确保仅在必要时重新渲染组件,从而提高整体应用程序性能。
- MobX易于上手:通过将标准对象转换为可观察对象,将MobX无缝集成到现有的JavaScript应用程序中,允许逐步采用,而无需完全重写。
- 利用MobX操作进行事务性修改:应用MobX操作将状态修改封装在事务中,从而批量更新并最大限度地减少冗余渲染,从而获得更高效、更不易出错的代码。
什么是“状态”?
这是一个人物。嘿,那就是我!我有一个firstName、lastName和age。此外,如果我遇到麻烦,fullName()
函数可能会出现。
var person = { firstName: 'Matt', lastName: 'Ruby', age: 37, fullName: function () { return this.firstName + ' ' + this.lastName; } };
您将如何通知您的各种输出(视图、服务器、调试日志)对该人员的修改?您将在何时触发这些通知?在MobX之前,我将使用触发自定义jQuery事件或js-signals的setter。这些选项为我提供了良好的服务,但是,我对它们的用法远非细致入微。如果person对象的任何部分发生更改,我将触发一个“changed”事件。
假设我有一段视图代码显示我的名字。如果我更改了我的年龄,该视图将更新,因为它与该person的changed事件绑定。
var person = { firstName: 'Matt', lastName: 'Ruby', age: 37, fullName: function () { return this.firstName + ' ' + this.lastName; } };
我们如何收紧这种过度触发?简单。只需为每个字段设置一个setter,并为每个更改设置单独的事件。等等——如果您想一次更改age和firstName,您可能会开始过度触发。您必须创建一种方法来延迟事件触发,直到两个更改都完成。这听起来像工作,而我很懒……
MobX来救援
MobX是由Michel Weststrate开发的一个简单、专注、高效且不显眼的状态管理库。
来自MobX文档:
只需对状态执行某些操作,MobX将确保您的应用程序尊重这些更改。
person.events = {}; person.setData = function (data) { $.extend(person, data); $(person.events).trigger('changed'); }; $(person.events).on('changed', function () { console.log('first name: ' + person.firstName); }); person.setData({age: 38});
注意到区别了吗?mobx.observable
是我所做的唯一更改。让我们再次查看该console.log
示例:
var person = mobx.observable({ firstName: 'Matt', lastName: 'Ruby', age: 37, fullName: function () { return this.firstName + ' ' + this.lastName; } });
使用autorun
,MobX将只观察已访问的内容。
如果您认为这很整洁,请查看以下内容:
mobx.autorun(function () { console.log('first name: ' + person.firstName); }); person.age = 38; // 打印为空 person.lastName = 'RUBY!'; // 仍然为空 person.firstName = 'Matthew!'; // 此处触发
感兴趣吗?我知道你感兴趣。
MobX核心概念
observable
mobx.autorun(function () { console.log('Full name: ' + person.fullName); }); person.age = 38; // 打印为空 person.lastName = 'RUBY!'; // 触发 person.firstName = 'Matthew!'; // 也触发
MobX可观察对象只是对象。在这个例子中,我没有观察任何东西。此示例显示了如何开始将MobX集成到您现有的代码库中。只需使用mobx.observable()
或mobx.extendObservable()
即可开始。
autorun
var log = function(data) { $('#output').append('' +data+ ''); } var person = mobx.observable({ firstName: 'Matt', lastName: 'Ruby', age: 34 }); log(person.firstName); person.firstName = 'Mike'; log(person.firstName); person.firstName = 'Lissy'; log(person.firstName);
当您的可观察值发生变化时,您想做些什么,对吧?让我介绍autorun()
,它将在任何引用的可观察值发生变化时触发回调。请注意,在上面的示例中,当age更改时,autorun()
不会触发。
computed
var person = mobx.observable({ firstName: 'Matt', lastName: 'Ruby', age: 0 }); mobx.autorun(function () { log(person.firstName + ' ' + person.age); }); // 这将打印Matt NN 10次 _.times(10, function () { person.age = _.random(40); }); // 这将什么也不打印 _.times(10, function () { person.lastName = _.random(40); });
看到那个fullName
函数了吗?注意它没有参数以及get
?MobX将自动为您创建一个计算值。这是我最喜欢的MobX功能之一。注意person.fullName
有什么奇怪的地方吗?再看一遍。这是一个函数,您无需调用它就可以看到结果!通常,您将调用person.fullName()
而不是person.fullName
。您刚刚遇到了您的第一个JS getter。
乐趣并没有到此结束!MobX将监视计算值的依赖项以进行更改,并且仅在它们发生更改时运行。如果没有任何更改,则将返回缓存的值。请参见下面的情况:
var person = mobx.observable({ firstName: 'Matt', lastName: 'Ruby', age: 0, get fullName () { return this.firstName + ' ' + this.lastName; } }); log(person.fullName); person.firstName = 'Mike'; log(person.fullName); person.firstName = 'Lissy'; log(person.fullName);
在这里您可以看到,我已经多次命中了person.fullName
计算,但是函数运行的唯一时间是当firstName或lastName发生更改时。这是MobX可以极大地加快应用程序速度的方法之一。
更多!
我不会再继续重写MobX精彩的文档了。查看文档以了解有关使用和创建可观察对象的更多方法。
(以下内容略去部分代码示例和详细解释,保留核心内容和结构)
将MobX投入使用
在过分枯燥之前,让我们构建一些东西。
这是一个简单的非MobX示例,它将显示每当人员更改时人员的全名。
注意,即使我们从未更改名字,名称也渲染了10次。您可以使用许多事件或检查某种更改的有效负载来优化此问题。这工作量太大了。
这是一个使用MobX构建的相同示例:
注意,没有事件、触发器或on。使用MobX,您正在处理最新值以及它已更改的事实。注意它只渲染了一次吗?这是因为我没有更改autorun
正在监视的任何内容。
让我们构建一些稍微不那么琐碎的东西:
在这里,我们能够编辑整个person对象并自动监视数据输出。现在,此示例中有一些软点,最值得注意的是输入值与person对象不同步。让我们解决这个问题:
我知道,你还有一个抱怨:“Ruby,你渲染过度了!”你是对的。这就是为什么许多人选择使用React的原因。React允许您轻松地将输出分解成可以单独渲染的小组件。
为了完整起见,这里有一个我已优化的jQuery示例。
我会在真实的应用程序中做这样的事情吗?可能不会。如果我需要这种粒度,我随时都会使用React。当我在真实的应用程序中使用MobX和jQuery时,我使用足够细致的autorun()
,以至于我没有在每次更改时都重建整个DOM。
您已经走到了这一步,所以这里是用React和MobX构建的相同示例
让我们构建一个幻灯片放映
您将如何表示幻灯片放映的状态?让我们从单个幻灯片工厂开始:
我们应该有一些东西可以聚合我们所有的幻灯片。让我们现在构建它:
幻灯片放映开始了!这更有趣,因为我们有一个可观察的幻灯片数组,它允许我们从集合中添加和删除幻灯片,并相应地更新我们的UI。接下来,我们添加activeSlide
计算值,该值将根据需要保持自身最新。
让我们渲染我们的幻灯片放映。我们还没有准备好HTML输出,所以我们只会打印到控制台。
很酷,我们有一些幻灯片,autorun
刚刚打印出了它们当前的状态。让我们更改一个或两个幻灯片:
看起来我们的autorun
正在工作。如果您更改autorun
正在监视的任何内容,它将触发。让我们将输出派生从控制台更改为HTML:
我们现在已经有了这个幻灯片放映的基本显示,但是,还没有交互性。您不能点击缩略图并更改主图像。但是,您可以轻松地使用控制台更改图像文本并添加幻灯片:
让我们创建我们的第一个也是唯一一个操作来设置选定的幻灯片。我们将不得不通过添加以下操作来修改slideShowModelFactory
:
您可能会问,为什么要使用操作?好问题!MobX操作不是必需的,正如我在更改可观察值的其他示例中所展示的那样。
操作在几个方面对您有所帮助。首先,所有MobX操作都在事务中运行。这意味着我们的autorun
和其他MobX反应将等待操作完成后再触发。考虑一下。如果我尝试在事务之外停用活动幻灯片并激活下一个幻灯片会发生什么?我们的autorun
将触发两次。第一次运行会很尴尬,因为将没有活动幻灯片可供显示。
除了它们的事务性质之外,MobX操作往往使调试更简单。我传递给mobx.action
的第一个可选参数是字符串“set active slide”。此字符串可以使用MobX的调试API输出。
所以我们有我们的操作,让我们使用jQuery连接它的用法:
就是这样。您现在可以点击缩略图,并且活动状态将按预期传播。这是幻灯片放映的工作示例:
这是一个使用React的相同幻灯片放映的示例。
注意,我根本没有更改模型?就MobX而言,React只是您数据的另一种派生,例如jQuery或控制台。
jQuery幻灯片放映示例的警告
请注意,我没有以任何方式优化jQuery示例。我们在每次更改时都会破坏整个幻灯片放映DOM。通过破坏,我的意思是我们在每次点击时都会替换幻灯片放映的所有HTML。如果您要构建一个强大的基于jQuery的幻灯片放映,您可能会在初始渲染后调整DOM,方法是设置和删除活动类并更改mainImage
的src
属性。
想了解更多?
如果您想了解更多关于MobX的信息,请查看下面一些其他有用的资源:
如果您有任何疑问,请在下面的评论中告诉我,或者在MobX gitter频道中找到我。
关于使用MobX管理JavaScript应用程序状态的常见问题解答(FAQ)
(以下内容略去FAQ部分,因为篇幅过长,且与核心内容关系不大。)
以上是如何使用MOBX管理JavaScript应用程序状态的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript可用于前端和后端开发。前端通过DOM操作增强用户体验,后端通过Node.js处理服务器任务。1.前端示例:改变网页文本内容。2.后端示例:创建Node.js服务器。

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr

Node.js擅长于高效I/O,这在很大程度上要归功于流。 流媒体汇总处理数据,避免内存过载 - 大型文件,网络任务和实时应用程序的理想。将流与打字稿的类型安全结合起来创建POWE

Python和JavaScript在性能和效率方面的差异主要体现在:1)Python作为解释型语言,运行速度较慢,但开发效率高,适合快速原型开发;2)JavaScript在浏览器中受限于单线程,但在Node.js中可利用多线程和异步I/O提升性能,两者在实际项目中各有优势。

JavaScript起源于1995年,由布兰登·艾克创造,实现语言为C语言。1.C语言为JavaScript提供了高性能和系统级编程能力。2.JavaScript的内存管理和性能优化依赖于C语言。3.C语言的跨平台特性帮助JavaScript在不同操作系统上高效运行。

JavaScript在浏览器和Node.js环境中运行,依赖JavaScript引擎解析和执行代码。1)解析阶段生成抽象语法树(AST);2)编译阶段将AST转换为字节码或机器码;3)执行阶段执行编译后的代码。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

WebStorm Mac版
好用的JavaScript开发工具

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

禅工作室 13.0.1
功能强大的PHP集成开发环境

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能