MobX记录

本博客 hjy-xh,转载请申明出处

说明

简单、可扩展的状态管理

优势

  • 简单直接

    • 编写无模板的极简代码来精准描述意图
  • 轻松实现最优渲染

    • 所有对数据的变更和使用都会在运行时被追踪到,并构成一个截取所有状态和输出之间关系的依赖树。这样保证了那些依赖于状态的计算只有在真正需要的时候才会运行,就像React组件一样。无需使用记忆化或选择器之类容易出错的次优技巧来对组件进行手动优化。
  • 架构自由

    • 它可以让你在任意UI框架之外管理你的应用状态。这样会使你的代码低耦合、可移植和更加容易测试

浏览器支持

  • Mobx >= 5 版本运行在任何支持 ES6 proxy的浏览器。
  • Mobx 4 可以运行在任何支持ES5的浏览器上,而且也讲进行持续地维护。MobX 4 和 5 的API是相同的,并且语义上也能达到相同的效果,只是Mobx 4 存在一些局限性
    • Observable 数组不是真正的数组,所以它们无法通过Array.isArray() 的检查。最常见的处理方法是在传递给第三方库之前,你经常需要先对其进行.slice()操作,从而得到一个浅拷贝的真正数组
    • 向一个已存在的 observable 对象中添加属性不会被自动捕获。要么使用 observable 映射来替代,要么使用工具函数中方法来对想要动态添加属性的对象进行读/写/迭代

核心概念

  • State(状态)

状态是驱动应用的数据。

可以用任何数据结构来存储状态,如JS基本数据类型、引用类型、普通对象、类实例、数组和映射

通常有像待办事项列表数据这样的领域特定状态,还有像当前已选元素的视图状态(状态就像是有数据的excel表格)

  • Action(动作)

Action(动作)是任意可以改变State(状态)的代码,比如用户事件处理、后端推送数据处理、调度器事件处理等

使用Action可以更好地组织代码,并防止在无意中修改State

如果是在严格模式下使用 MobX的话,MobX 会强制只有在动作之中才可以修改状态

  • Derivations(派生)

任何来源是State并且不需要进一步交互的东西都是Derivation
多种形式:

  • 用户界面
  • 派生数据,比如剩下的待办事项的数量
  • 后端集成,比如把变化发送到服务器端
    两种类型:
  • Computed values(计算值) 它们是永远可以使用纯函数从当前可观察状态中衍生出的值
  • Reactions(反应)他们是当状态改变时需要自动发生的副作用 (命令式编程和响应式编程之间的桥梁,或者说得更明确一些,它们最终都需要实现I / O 操作)

黄金法则:如果想创建一个基于当前状态的值时,使用computed

原则

MobX使用单向数据流,利用Action改变State,进而更新所有受影响的View

  • 所有的Derivations将在State改变时自动且原子化的更新,引测不可能观察中间值
  • 所有的Derivations默认将会同步更新,这意味着Action可以在State改变之后安全的直接获取computed值
  • Computed value的更新是惰性的,任何Computed value在需要它们的副作用发生之前都是不激活的
  • 所有的Computed value都应该是纯函数,它们不应该修改State

工作原理

MobX使用Object.defineProperty来拦截对数据的访问,一旦值发生变化,就会调用Reactrender方法重新渲染视图或者触发autorun

常用API

  • Autorun

    • 用法:autorun(effect: (reaction) => void)
    • 说明:autorun 函数接受一个函数作为参数,每当该函数所观察的值发生变化时,它都应该运行。 当你自己创建 autorun 时,它也会运行一次
  • Reaction

    • 用法:
      • 5:reaction(() => data, (data, reaction) => { sideEffect }, options?)
      • 6:reaction(() => value, (value, previousValue, reaction) => { sideEffect }, options?)
    • 说明:
      • reaction 类似于 autorun,但可以让你更加精细地控制要跟踪的可观察对象。 它接受两个函数作为参数:第一个,data 函数,其是被跟踪的函数并且其返回值将会作为第二个函数,effect 函数,的输入。 重要的是要注意,副作用只会对 data 函数中被访问过的数据做出反应,这些数据可能少于 effect 函数中实际使用的数据
      • 一般的模式是在 data 函数中返回你在副作用中需要的所有数据, 并以这种方式更精确地控制副作用触发的时机。 与 autorun 不同,副作用在初始化时不会自动运行,而只会在 data 表达式首次返回新值之后运行
  • When

    • 用法:
      • when(predicate: () => boolean, effect?: () => void, options?)
      • when(predicate: () => boolean, options?): Promise
    • 说明:when 会观察并运行给定的 predicate 函数,直到其返回 true。 一旦 predicate 返回了 true,给定的 effect 函数就会执行并且自动执行器函数将会被清理掉。

集成React

MobX 可以独立于 React 运行, 但是他们通常是结合在一起使用

常用的两个包:

  • mobx-react
  • mobx-react-lite

mobx-react中引用了mobx-react-lite包,它提供了很多在新项目中不再需要的特性,其中有:

  • 对于React class components的支持
  • Provider 和 inject ,MobX的这些东西在有React.createContext替代后变得不必要了
  • 特殊的观察对象 propTypes

要注意 mobx-react 是全量包,也会暴露 mobx-react-lite包中的任何方法,其中包含对函数组件的支持。 如果你使用 mobx-react,那就不要添加 mobx-react-lite 的依赖和引用了

注意事项

  • 区分computedauturun
    如果想响应式的产生一个可以被其它observer使用的值,使用@compouted;如果想要达到一个效果,使用autorun(打印日志,发起网络请求等这样命令式的副作用)

参考

MobX 中文文档

MobX