带你走进Mobx的原理

https://user-gold-cdn.xitu.io/2019/3/11/1696aaaf5d42f088?w=800&h=800&f=png&s=26678

Mobx相信大家都听过,也有部分同学用过,在状态管理界,和Redux同日争辉。在本文中,将通过介绍Mobx的核心概念、设计原则及问答形式的方式,带大家走进Mobx的世界,一窥其中的原理。原文地址:leeing.site/2019/03/15/…

核心概念

可观察状态(Observable state)

状态是驱动应用的数据。通常有像待办事项列表这样的领域特定状态,还有像当前已选元素的视图状态。记住,状态就像是有数据的excel表格。

衍生(Derivations)

任何源自状态并且不会再有任何进一步的相互作用的东西就是衍生。衍生以多种形式存在

  • 用户界面
  • 衍生数据,比如剩下的待办事项的数量
  • 后端集成,比如把变化发送到服务器端

Mobx区分了两种类型的衍生

  • 计算值(Computed values),它们是永远可以用纯函数从当前可观察状态中衍生出的值
  • 反应(Reactions),它们是当状态改变时需要自动发生的副作用,用来连接命令式编程和响应式编程,最终都需要实现I/O操作,例如发送请求,更新页面等。

动作(Actions)

动作是任意一段可以改变状态的代码。用户事件,后端数据推送等。

Mobx中可以显示地定义动作,它可以帮你把代码组织的更清晰。严格模式下,Mobx强制要求只有Action可以修改状态。

设计原则

Mobx支持单向数据流,也就是动作改变状态,而状态的改变会更新所有受影响的图。

Action —> State —> Views

当状态改变时,所有衍生都会进行原子级的自动更新。因此永远不可能观察到中间值。

所有衍生默认都是同步更新的。这意味着动作可以在改变状态之后直接可以安全地检查计算值。

计算值是延迟更新的。任何不在使用状态的计算值将不会更新,直到需要它进行副作用(I/O)操作时。如果视图不再使用,那么它会自动被垃圾回收。

所有的计算值都应该是纯净的。它们不应该用来改变状态。

https://user-gold-cdn.xitu.io/2019/3/11/1696aaaf5b397f77?w=1407&h=483&f=png&s=79147

原理

重要思想:在运行时才能实现最小、一致地订阅子集

问:Mobx如何有效地将所有衍生保持在一个一致地状态? 答:不缓存数据,在需要时重新计算。Mobx认为这是很高效地,因为Mobx不会计算所有衍生,只会计算确保参与反应的计算。这被称为响应式地。

问:没有参与反应的衍生呢? 答:如果一个衍生没有被激活,它将被按需处理。就像一个普通的getter函数一样,懒衍生如果没有用了,将被简单的垃圾回收。所有computed需要使用纯函数,因为对于纯函数而言,是懒衍生还是直接使用并不重要,在相同的状态下,总是返回相同的结果。

问:当状态变化时,衍生是如何计算的? 答:当重新计算被触发时,衍生函数将被压入到衍生堆栈中。只要计算正在运行,每个被访问的状态都会将自身注册为衍生堆栈最顶层函数的依赖项。当计算值被需要了,如果该值已经处于reactive状态,则该值可以简单最后已知的值,否则它将push自己到衍生堆栈中,切换到reactive模式并开始计算,具体计算过程如下:

  1. 可观察值像所有观察者发送过时通知,表明它已经变得陈旧。任何受影响的衍生将以递归的 方式将通知传递给其观察者。因此,依赖关系树的一部分将被标记为陈旧。

  2. 在发送陈旧通知并存储新值后,一个就绪通知将被发送,用于指示该值是否确实发生了变化

  3. 一旦衍生收到步骤1中每个陈旧通知的就绪通知,它就会知道所有的被观察值都稳定了,于是将 开始重新计算。计算就绪和陈旧消息的数量可以确保这一点。

  4. 如果没有就绪通知指出一个值变化了,衍生将直接告诉自己的观察者它已经准备好了且没有变 化中的值

同步执行 Mobx同步运行所有内容。这有2大好处:

  1. 不可能观察陈旧的衍生
  2. 追踪堆栈和调试变得简单

Mobx还提供事务机制。事务推迟所有就绪通知,直到事务块执行完成后,同步运行和更新所有内容。

https://user-gold-cdn.xitu.io/2019/3/11/1696aaaf5e1981e0?w=405&h=126&f=png&s=23207

对比Redux

  1. Redux将数据保存在单一store中,Mobx将数据保存在分散的多个store中
  2. Redux需要手动处理变化后的操作,Mobx使用observable保存数据,数据变化后自动处理响应的操作
  3. Redux使用不可变状态,不能直接去修改它,而是应该使用纯函数返回一个新的状态;Mobx中的状态是可以直接修改的

参考链接

猜你喜欢

转载自juejin.im/post/5c8a8158e51d453196293cf5