自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一篇帶你揭秘 MobX 實現(xiàn)原理

開發(fā) 項目管理
mobx 是熱度僅次于 redux 的狀態(tài)管理庫,它和 redux 有相同的地方也有不同的地方。

mobx 是流行的狀態(tài)管理庫,熱度僅次于 redux。它和 redux 有的地方一樣,也有的地方不一樣:

一樣的地方是 mobx 和 redux 都是單向數(shù)據(jù)流,通過 action 觸發(fā)全局 state 更新,然后通知視圖。

redux 的數(shù)據(jù)流:

mobx 的數(shù)據(jù)流:

但是它們修改狀態(tài)的方式不一樣:

redux 是每次返回一個全新的狀態(tài),一般搭配實現(xiàn)對象 immutable 的庫來用。

mobx 每次都是修改的同一個狀態(tài)對象,基于響應(yīng)式代理,也就是 Object.defineProperty 代理 get、set 的處理,get 時把依賴收集起來,set 修改時通知所有的依賴做更新。和 vue2 的響應(yīng)式代理很類似。

其中,redux 那種方式是函數(shù)式的思路,所以狀態(tài)的修改都在一個個 reducer 函數(shù)里,而 mobx 那種方式則是面向?qū)ο蟮拇淼乃悸罚院苋菀装? state 組織成一個個 class。

這也就導(dǎo)致了兩種狀態(tài)管理方式的代碼組織是有區(qū)別的:

redux 是在 reducer 函數(shù)里組織狀態(tài)(函數(shù)式的特點):

const reducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
};

而 mobx 則是在 class 里組織狀態(tài)(面向?qū)ο蟮奶攸c):

import {observable, action} from 'mobx';
class Store {
@observable number = 0;
@action add = () => {
this.number++;
}
}

此外,redux 那種方式每次都要返回一個新的對象,雖然可以用 immutable 的庫來減少創(chuàng)建新對象的開銷,但是比起 mobx 直接修改原對象來說,開銷還是大一點。

而且 redux 通知依賴更新的時候是全部通知的,而 mobx 因為收集了每個屬性的依賴,可以精準(zhǔn)的通知。

所以 mobx 的性能會比 redux 高一些。

綜上,mobx 和 redux 都是單向數(shù)據(jù)流,但是管理狀態(tài)的思路上,一個是函數(shù)式的思想,通過 reducer 函數(shù)每次返回新的 state,一個是面向?qū)ο蟮乃枷耄ㄟ^響應(yīng)式對象來管理狀態(tài),這導(dǎo)致了狀態(tài)組織方式上的不同(function/class),而且 redux 創(chuàng)建新的 state 的開銷還有通知所有依賴的開銷都比 mobx 大,性能比 mobx 差一些。

對比下來,我們會發(fā)現(xiàn) mobx 似乎比 redux 優(yōu)秀一些。那我們具體看下 mobx 怎么用吧:

mobx 的使用

官方提供的 demo 是這樣的:

import React from "react"
import ReactDOM from 'react-dom';
import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react"
class Timer {
secondsPassed = 0
constructor() {
makeAutoObservable(this)
}
increase() {
this.secondsPassed += 1
}
reset() {
this.secondsPassed = 0
}
}
const myTimer = new Timer()
const TimerView = observer(({ timer }) => (
<button onClick={() => timer.reset()}>Seconds passed: {timer.secondsPassed}</button>
))
setInterval(() => {
myTimer.increase()
}, 1000);
ReactDOM.render(<TimerView timer={myTimer} />, document.getElementById('root'));

就像前面說的,mobx 基于響應(yīng)式對象來管理狀態(tài),所以組織狀態(tài)是用 class 的形式。

我們聲明了 Timer 的 class,有一個屬性是 secondsPassed 代表過去了幾秒,有兩個方法來修改它。

在構(gòu)造器里調(diào)用 makeAutoObservable 來創(chuàng)建響應(yīng)式的代理。

然后 new 一個 Timer 的對象,傳到組件里,組件使用 observer 的高階組件包裹,它負(fù)責(zé)把被包裹的組件添加到 timer 的響應(yīng)式依賴中去。

然后把這個組件渲染到 dom。

這樣就完成了 mobx 和 react 的結(jié)合使用,看下效果:

我們是把時間(secondsPassed)放在 mobx 的全局 state 中管理的,在組件里使用,然后定時更新它。發(fā)現(xiàn)每次更新組件都得到了通知并做了渲染,這就是全局狀態(tài)管理的功能。

demo 里我們用的 makeAutoObservable 函數(shù),它會自動給屬性添加響應(yīng)式代理,方法會添加一層觸發(fā) action 的代理。

也可以手動標(biāo)識:

import { observable, action } from "mobx"
class Timer {
@observable secondsPassed = 0
constructor() {
}
@action increase() {
this.secondsPassed += 1
}
@action reset() {
this.secondsPassed = 0
}
}

我們大概知道了 mobx 怎么用,那它是怎么實現(xiàn)的呢?

接下來我們從源碼來理一下它的實現(xiàn)原理:

mobx 的實現(xiàn)原理

首先,mobx 會對對象做響應(yīng)式代理,那代理以后的對象是什么樣的呢?

我們打印下:

原始對象的 secondsPassed 屬性是 0,increase 和 reset 方法體修改 secondsPassed 的值。

而代理以后的對象屬性分為了 get 和 set,并且實現(xiàn)變成了 this[$mobx].getObservablePropValue 和 setObservablePropValue,這明顯是做了響應(yīng)式的處理了。

代理以后的方法都變成了 excuteAction,執(zhí)行方法會 dispatch 一個 acition。

那這個響應(yīng)式的代理是怎么實現(xiàn)的呢?

跟蹤 makeAutoObservable 的源碼會發(fā)現(xiàn) mobx 創(chuàng)建了一個 ObservableObjectAdministration 的對象放到了 $mobx 屬性上。

在 timer 對象確實是有這個屬性的:

用 Symbol 聲明了一個私有屬性 mobx administration 來放 ObservableObjectAdministration 對象。

然后還用 Symbol 聲明了一個私有屬性。mobx-keys 來放所有做了代理的屬性和方法名。

那這個 ObservableObjectAdministration 對象是干啥的呢?

看下它的定義:

可以看到它有 values 屬性記錄每個 key 的依賴。

還有 getObservableValue 和 setObservableValue 來獲取和設(shè)置某個 key 的值。這兩個方法就是被代理后的屬性的 get set 最終調(diào)用的方法:

這不就串起來了么:

創(chuàng)建對象的時候 mobx 會對屬性和方法做代理,會添加一個 Symbol(mobx administrator) 屬性到對象上來保存 ObservableObjectAdministration 對象,它是用來記錄屬性的所有依賴的,對屬性的 get 和 set 都會被代理到這個 ObservableObjectAdministration 的 getXxx 和 setXxx 方法上。

我們打印下這個對象看看:

確實,values 里保存了唯一一個屬性和它的所有依賴。

至此,對對象做響應(yīng)式代理的流程我們已經(jīng)理清了:

那這個依賴是什么時候收集的呢?

我們繼續(xù)往下看 get 收集依賴和 set 觸發(fā)依賴更新的部分:

我們用 observable 包裹了組件,它是一個高階組件,對組件做一層代理,返回新的組件:

在這層代理里面,創(chuàng)建了 Reaction 對象,也就是收到更新的通知之后怎么做出反應(yīng),在回調(diào)函數(shù)里用 setState([]) 的方式實現(xiàn)了強(qiáng)制更新。

并且,這層高階組件的代理里會把當(dāng)前組件設(shè)置到全局,這樣后面做 get 的依賴收集的時候就能拿到對應(yīng)的組件了。

所以在組件里用到 state 的 get,做依賴收集時,就知道當(dāng)前是哪個組件了:

當(dāng)然,這里收集的不是具體哪個組件,而是 onInvalidate 的回調(diào)函數(shù),也就是收到更新的通知之后如何做出反應(yīng)。

這樣就完成了依賴的收集,在后面修改響應(yīng)式對象的狀態(tài)屬性的時候,就會觸發(fā)依賴,然后實現(xiàn)組件的更新:

這樣,我們就串聯(lián)起了 mobx 的響應(yīng)式原理:

總結(jié)

mobx 是熱度僅次于 redux 的狀態(tài)管理庫,它和 redux 有相同的地方也有不同的地方:

相同的地方是都是單向數(shù)據(jù)流。

不同的地方是 redux 是函數(shù)式思想的實現(xiàn),通過 reducer 函數(shù)管理狀態(tài),一般會用 immutable 的庫來提高創(chuàng)建新對象的性能。而 mobx 是面向?qū)ο蟮乃枷?,通過響應(yīng)式代理來管理狀態(tài),可以通過 class 組織 state。

性能方面 mobx 的響應(yīng)式能精準(zhǔn)的通知依賴做更新,而 redux 只能全局通知,而且 mobx 只是修改同一個對象,不是每次創(chuàng)建新對象,性能會比 redux 更高。

然后我們又通過一個 demo 來入門了下 react 中使用 mobx:通過 class 組織狀態(tài),然后創(chuàng)建響應(yīng)式代理,組件用 observer 高階組件做一層包裝,傳入 mobx 的對象,這樣 mobx 和組件就結(jié)合到了一起,狀態(tài)更新就能通知到組件。

之后我們從源碼層面理清了 mobx 的響應(yīng)式機(jī)制的實現(xiàn)原理:mobx 會在對象上添加一個 Symbol($mobx) 的隱藏屬性,用來放 ObservableObjectAdministration 對象,它是用于管理屬性和它的依賴的,在 get 的 時候收集依賴,然后 set 的時候就可以通知所有收集到的依賴(Reaction)做更新。

看到這里,你是否對 mobx 的特點和原理有更深的理解了呢?

責(zé)任編輯:姜華 來源: 神光的編程秘籍
點贊
收藏

51CTO技術(shù)棧公眾號