mobx是一个流行的状态管理库,流行度仅次于redux。和redux有的地方一样,有的地方不一样:相同的地方是mobx和redux都是单向数据流,通过action触发全局状态更新,然后通知view。redux的数据流:mobx的数据流:但它们修改状态的方式不同:redux每次都返回一个新的状态,一般与实现不可变对象的库一起使用。mobx每次修改同一个状态对象,基于响应式代理,即Object.defineProperty代理get和set处理,get时收集依赖,set修改时通知所有依赖更新。很像vue2的响应式代理。其中redux的方式是函数式的思维方式,所以state的修改是在每个reducer函数中,而mobx的方式是面向对象代理的方式,所以很容易将state组织成类.这也导致了两种状态管理方式在代码组织上的差异:redux将状态组织在reducer函数中(功能特点):constreducer=(state=0,action)=>{switch(action.type){case'INCREMENT':返回状态+1;case'DECREMENT':返回状态-1;默认值:返回状态;}};mobx在类中组织状态(面向对象的特性):import{observable,action}from'mobx';类商店{@observablenumber=0;@actionadd=()=>{this.number++;另外,redux方法每次都返回一个新的对象,虽然可以使用不可变库来减少创建新对象的开销,但是相比mobx直接修改原始对象,开销还是大了一点。而且,redux会在更新时通知所有依赖项,而mobx可以准确通知,因为它收集了每个属性的依赖项。所以mobx的性能会比redux高。综上,mobx和redux都是单向数据流,但是在状态管理思想上,一个是函数式的思想,通过reducer函数每次返回一个新的状态,一个是面向对象的思想,它由一个响应式对象State管理,导致不同的状态组织方式(函数/类),redux创建新状态和通知所有依赖的开销比mobx大,性能比mobx差。相比之下,我们会发现mobx似乎比redux要好。下面来看看mobx的详细使用方法:mobx官方提供的demo如下:react"classTimer{secondsPassed=0constructor(){makeAutoObservable(this)}increase(){this.secondsPassed+=1}reset(){this.secondsPassed=0}}constmyTimer=newTimer()constTimerView=观察者(({timer})=>(timer.reset()}>经过的秒数:{timer.secondsPassed}))setInterval(()=>{myTimer.increase()},1000);ReactDOM.render(,document.getElementById('root'));前面说过,mobx是基于响应式对象来管理状态的,所以组织状态的方式是类的形式。我们声明了Timer这个类,一个属性是secondsPassed,表示经过的秒数,有两个方法可以修改。在构造函数中调用makeAutoObservable以创建反应式代理。然后创建一个新的Timer对象并将其传递给组件。组件用观察者的高层组件包裹起来,它负责将包裹后的组件添加到定时器的响应依赖中。然后将这个组件渲染到dom中。这样就完成了mobx和react的结合使用。看看效果:我们在mobx的全局状态中管理时间(secondsPassed),在组件中使用,然后定时更新。发现每次组件更新时,都会通知并渲染,这是全局状态管理的作用。我们在demo中使用的makeAutoObservable函数会自动为属性添加一个响应式代理,该方法会添加一层触发动作的代理。也可以手动标记:import{observable,action}from"mobx"classTimer{@observablesecondsPassed=0constructor(){}@actionincrease(){this.secondsPassed+=1}@actionreset(){this.secondsPassed=0}}我们大概知道mobx是如何工作的,那么它是如何实现的呢?接下来我们从源码上看一下它的实现原理:mobx的实现原理首先,mobx会作为对象的响应式代理,而代理的未来对象长什么样?打印一下:原对象的secondsPassed属性为0,increase和reset方法体修改了secondsPassed的值。代理之后对象属性分为get和set,实现就变成了this[$mobx].getObservablePropValue和setObservablePropValue,显然是一个响应式的过程。proxy之后的methods变成了executeAction,execution方法会派发一个action。那么这个响应式代理是如何实现的呢?追溯makeAutoObservable的源码会发现,mobx创建了一个ObservableObjectAdministration对象,放在$mobx属性上。timer对象确实有这个属性:使用Symbol声明一个私有属性mobxadministration来保存ObservableObjectAdministration对象。然后还用Symbol声明一个私有属性。mobx-keys放置所有已被代理的属性和方法名称。那么这个ObservableObjectAdministration对象有什么作用呢?看它的定义:可以看到它有一个values属性,用来记录每个key的依赖关系。还有getObservableValue和setObservableValue来获取和设置键的值。这两个方法是proxied属性的get集合最终调用的方法:这不是字符串吗:mobx在创建对象的时候会作为属性和方法的代理,会添加一个Symbol(mobx管理员)property到对象上来保存ObservableObjectAdministration对象,这个对象用来记录属性的所有依赖关系,属性的get和set会代理到这个ObservableObjectAdministration的getXxx和setXxx方法。让我们打印这个对象看看:确实,唯一的属性及其所有依赖项都存储在值中。至此,我们就把对象做响应式代理的过程搞清楚了:这个依赖是什么时候收集的?我们继续看get收集依赖和set触发依赖更新的部分:我们用observable包装组件,它是一个高层组件,为组件做一层代理,并返回一个新的组件:在这一层proxy,创建一个Reaction对象,即收到更新通知后如何反应,使用setState([])实现强制更新。另外,这一层高层组件的代理会把当前组件设置为全局级别,这样后面做get的依赖收集的时候就可以获取到对应的组件。所以在组件中使用stateget,在做依赖收集的时候,就会知道当前是哪个组件:当然这里收集的并不是具体的组件,而是onInvalidate的回调函数,也就是接收到之后要做什么更新通知响应。这样就完成了依赖的收集。后面修改响应式对象的状态属性时,会触发依赖,进而更新组件:这样,我们串联了mobx的响应式原理:综上所述,mobx仅次于流行对于redux的状态管理库,它和redux有相同也有不同的地方:相同的地方是单向数据流。不同的是redux是函数式思想的实现。通过reducer函数管理状态,不可变库一般用于提高创建新对象的性能。而mobx是面向对象的思想,通过响应式代理来管理状态,可以通过类来组织状态。在性能上,mobx的响应式可以准确通知依赖更新,而redux只能全局通知,而且mobx只修改同一个对象,而不是每次都创建一个新的对象,性能会比redux高。然后我们用一个demo开始在react中使用mobx:通过class来组织state,然后创建响应式代理,用observer高层组件包裹组件,传入mobx的对象,这样mobx和components就可以了结合在一起,可以将状态更新通知给组件。然后我们从源码层面明确了mobx响应式机制的实现原理:mobx会给对象添加一个Symbol($mobx)的隐藏属性,用来放ObservableObjectAdministration对象,这个对象用来管理属性及其依赖,在获取的时候收集依赖,然后在设置的时候通知所有收集到的依赖(Reaction)去更新。看到这里,是不是对mobx的特点和原理有了更深入的了解呢?