Build your own Mobx

Tags
React
Web Dev
Published
December 11, 2021
Author
HJS
有很多人写关于 React 状态管理对比的文章,但其实一般来说,如果你了解过各种方案的设计思想,就可以节省在上面花费的大量时间,让我们一起实现一个简单的 Mobx。
建议结合代码食用,点击标题可直接跳转相关代码
 

Observable

observable 方法用于创建可观察对象。实现思路是代理对象 set、get、deleteProperty,在 get 时收集 observer,set 时触发 observer,deleteProperty 时清空 observer。
 

Event 和 proxies

Event 是观察者模型的抽象,proxies 则是一个储存 observer 的对象,签名为
type Target = object //可观察对象 type EventMap = { [propName: string]: Set<Function> } //属性和 observer 的 Set 列表 proxies = new WeakMap<Target, EventMap>()
  • 使用 WeakMap,当有且只有 proxies 对象引用 target 时,target 会被垃圾回收。
  • 使用 Set 储存 observer,收集时自动去重
 

Action

action 方法将函数放进事务内部运行,用于批量更新。实现思路是统计调用栈深度,当深度不为零时,set 可观察属性并不会立即通知 observer,而是将其放进一个 Set 中去重,并在深度为零时遍历调用 observer。
 

Autorun

autorun 函数接受一个函数作为参数,每当该函数所观察的值发生变化时,它都应该运行。实现思路是在 get 前后设置该函数,将其作为可观察属性的 observer。—— 代码
需要注意的一点是只有可观察属性使用到时才会绑定该函数,因此需要 wrap 一层做惰性绑定。
 

Reaction

reaction 类似于 autorun,但可以让你更加精细地控制要跟踪的可观察对象。 它接受两个函数作为参数:第一个,data 函数,其是被跟踪的函数并且其返回值将会作为第二个函数,effect 函数,的输入。 重要的是要注意,副作用只会对 data 函数中被访问过的数据做出反应,这些数据可能少于 effect 函数中实际使用的数据。
实现思路类似 autorun,运行 data 函数并收集 effect 函数作为 observer。
  • 通过引用的方式传递 data 函数的返回结果给 effect 函数。
  • reaction 需要返回 dispose 函数,用于清除该 effect 函数。
 

Observer

observer HOC 将自动订阅 React components 中任何在渲染期间被使用的可被观察的对象 。 因此, 当任何可被观察的对象变化发生时候组件会自动进行重新渲染。 它还会确保组件在没有变化发生的时候不会进行重新渲染。
observer 是 mobx-react 中的概念,本质上是个 HOC。实现思路是在组件首次 render 时使用 Reaction 收集依赖,将 forceUpdate 作为其 observer。
  • 使用 React.memo 优化性能
  • 组件 unmount 时需要清除掉 observer
 

总结

到这里我们已经实现了一个简易的 Mobx,总的来看就是 Proxy + 观察者模式 + 事务 + React HOC,如果照着注释还是对细节有不理解的地方,就通过断点调试一步步走完流程吧,sourcemap 相关配置已经配置在代码中。