Mobx是一个状态管理的库, 也许你对应用中一些数据的管理已经驾轻就熟了,而且有本身擅长或喜爱的状态管理库,但这也并不会影响你对Mobx展开了解,由于这些库或者工具提供给咱们的是解决问题的方案,存在即有其合理性,既然Mobx存在,并受到很多人的推崇,那确定有其优点所在,基于这个缘由,咱们也是能够花那么一丢丢时间去熟悉下的,也许会对咱们有莫大的帮助。我也是基于这么个想法去了解熟悉了下mobx,并作个总结。vue
mobx是一个状态管理的库,它不依赖于视图层的框架, 不像vuex,是vue的定制版。它与任何的视图层框架都是能够配合使用的, 可是和它最配的就是React了。但是React不是已经有了黄金搭档Redux么, 为啥还出来一个第三者呢,而且还受到很多人的喜好, 连Redux的做者都推荐过mobx,还有很多人将应用从Redux重构为Mobx。这说明Mobx确实有其吸引人的地方,这里不谈二者的对比,这一系列文章仍是比较多的,不过能够先从这里入手一波Mobx。react
Demo1:
import { observable, autorun } from 'mobx'
const obsObj = observable({
title: 'hello world'
})
autorun(() => {
console.log('mobx observal title',obsObj.title)
})
obsObj.title = 'title change'
复制代码
输出的结果是:git
otuput:
mobx observal title: hello world
mobx observal title: title change
复制代码
将一个对象经过observable方法变为可观察的, 执行aurorun中的函数, 状态变动后autorun中的函数自动的再次执行。能够看出Mobx自身实现了一套响应式原理,没读过源码, 但大体能够知道其实现使用了观察者模式,第一遍执行autorun时有调用对象属性的对方对其get方法进行拦截, 并将这个函数加入到其依赖中, 在执行set的时候,执行收集的依赖。其中autorun就是原来图中的reaction衍生, state就是observable以后的可观察状态对象。github
Demo2:
import {observable, autorun, action} from 'mobx'
const obsObj = observable({
title: 'hello world',
get extendTitle() {
return `${this.title} mobx`
}
})
autorun(() => {
console.log('mobx computed title:', obsObj.extendTitle)
})
const fn = action(function(){
obsObj.title = 'title change'
})
fn()
复制代码
输出结果是:vuex
otuput:
mobx computed title:' hello world mobx mobx observal title: title change mobx 复制代码
相比上个例子,多了一个computed属性, 即extendTitle, 它也是会变为可观测的, 能够知道extendTitle依赖了title,因此title变了后, computed自动生成新的值,而autorun依赖的extendTitle变了,因此再次自动执行。(值得注意的是若没有计算属性是只有运用到时才会去执行从新计算逻辑)。还有一个action, 它是将要变动数据的方法用action包裹一下, 这个不是必须的, 可是在大型复杂应用中这是颇有必要的,由于状态的变动必定是发生在action里, 更容易定位问题。 所以mobx有配置参数能够设置更改observable的数据必需要用action包裹。chrome
至此mobx的执行流程以及重要的概念已经经过上述的两个demo比较清晰的理解了。redux
mobx的api也是比较简单而且好理解的,能够将其分为 三类, 上面的demo中使用的api都有各自的归属, 这部分简单讲下这三类api,固然是自我理解后的一些精华部分, 具体并完整的那莫过于官网了, 而且也不是一篇文章能讲完的。api
mobx能够将JS基本数据类型、引用类型、普通对象、类实例、数组、映射、Set变为一个可观察的数据。数组
这是一个便捷的api,observable(value), 只有value是object(普通对象), Array, Map, Set能转换成功。原始数据类型、非普通对象、函数会报错。 注: 普通对象指的是一个对象的原型是Object,或者没有原型,即用花括号建立的对象字面量或者Object.create(null)建立的对象promise
能够是任何数据,通常用于基本数据类型,设置和获取以及变为可观测的使用方式和observable有所不一样。例如官网的一个demo:
import {observable} from "mobx";
const cityName = observable.box("Vienna");
console.log(cityName.get());
cityName.observe(function(change) {
console.log(change.oldValue, "->", change.newValue);
});
cityName.set("Amsterdam");
复制代码
extendObservable用于将用构造函数生成的对象以及Object.create原型非null的对象变为可观察。
var Person = function(firstName, lastName) {
// 在一个新实例上初始化 observable 属性
extendObservable(this, {
firstName: firstName,
lastName: lastName,
get fullName() {
return this.firstName + " " + this.lastName
},
setFirstName(firstName) {
this.firstName = firstName
}
}, {
setFirstName: action
});
}
var matthew = new Person("Matthew", "Henry");
extendObservable(matthew, {
age: 353
});
复制代码
以上几个api基本上完成了绝大多数咱们应用的诉求,将数据变为可观察。
reactions指的是对可观察的数据作出相应,能够是产生一个新的值, 也能够是产生一些反作用, 好比打印日志,更新视图等的逻辑。
很是好理解的一个api, 就是计算属性, 会根据依赖的可变化数据生成一个新的值, 而且这个新的值也是可观察。mobx对性能上是作到了很好的优化的,这个计算属性的值,在某轮状态变化的过程当中没有被用到,那么它是不会被从新计算执行的,而且若是这个值再也不被引用了, 那么也会被垃圾回收掉。
这个就是响应式函数, 依赖的状态变化后, 自动执行该函数, so easy。
这两个彻底能够看作是autorun的语法糖,是autorun功能的一个加强。官网看下api很是好理解的。
注意点: 咱们要弄清楚衍生它会对什么作出响应,MobX 会对在追踪函数执行过程当中读取现存的可观察属性作出反应。就是在衍生里执行了读取可观察属性的操做,则它会响应后续的状态变动。
action就是动做, 触发可观察状态的变动, 造成一个闭环,从上面的两个demo其实能够看出,action包裹并非必须的,可是大型应用中将一些数据变动的操做都强制用action包裹是颇有必要的, 这样对系统的维护性以及排查问题仍是颇有用的。
若是须要将动做强制action包裹, 须要全局配置mobx的config:
const { configure} from "mobx"
configure({
enforceActions: 'always'
});
复制代码
若是action包裹的函数中存在异步的回调函数(promise的then,setTimeout里的回调), 若是里面改变了状态则也须要用将其用action包裹,runInAction它也是action的语法糖, 将异步回调中的最终的状态修改的部分放到一个函数中,用runInAction包裹。
将异步用generator的方式写,而后用flows包裹。
上面的那些三类api就是mobx的思想所在, 可是mobx正真方便使用姿式是装饰器模式。以下使用装饰器的两个demo所示, 包含以上三类api的使用:
demo1:
import { observable, computed, autorun } from "mobx";
class OrderLine {
@observable price = 0;
@observable amount = 1;
@computed get total() {
return this.price * this.amount;
}
}
const obj = new OrderLine()
autorun(() => {
console.log(obj.amount)
})
obj.amount = 2
复制代码
上述是在babel或者ts的转换下,支持用装饰器写法的一个coding, 若是不支持, 也提供了decator api以下:
demo2:
import { observable, computed, action, decorate } from "mobx"
class OrderLine {
price = 0;
amount = 1;
get total() {
return this.price * this.amount;
}
setPrice() {
this.price = 2
}
}
decorate(OrderLine, {
price: observable,
amount: observable,
total: computed,
setPrice: action,
})
复制代码
mobx内置了trace API,该API能够帮助咱们在开发的时候进行调试。能够经过在衍生中(computed,autorun等响应函数)加入trace(true),可以在响应状态变化时进行debugger,经过调试信息咱们可以看出是哪一个状态的变化触发了它的响应、这个衍生依赖哪些状态,以及定位这次变化的代码。
Demo:
import {observable, autorun, trace} from 'mobx'
const obsObj = observable({
title: 'hello world',
name: 'trace demo'
})
autorun((r) => {
trace(true)
console.log('name: ', obsObj.name)
})
obsObj.name = 'title changed'
复制代码
上面demo中,可观察状态obsObj.name发生变化时,自动执行autorun, 而后在chrome能够看到以下的断点信息:
经过上述mobx的了解,大概知道其如何运行以及一些重要的api,它是不依赖于视图层框架的, 即它能够和咱们主流的React、VUE、Angular结合的,只须要一个链接器,但它还算和React搭配运用的最多了。友mobx原理不难理解, 只须要将视图的render做为一个衍生就好了,render里的状态都变为可观察的,状态变了就从新render,更新视图。即以下图所示:
以上是mobx一些主要的思想以及api, 经过这边文章能够用更少的时间去了解上手mobx, 若是须要深刻能够仔细去研读mobx的官网了,以及mobx和redux的对比文章也是能够搜索出很多的。