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

聊聊MobX 上手指南

開(kāi)發(fā) 前端
之前用 Redux 比較多,一直聽(tīng)說(shuō) Mobx 能讓你體驗(yàn)到在 React 里面寫(xiě) Vue 的感覺(jué),今天打算嘗試下 Mobx 是不是真的有寫(xiě) Vue 的感覺(jué)。

[[378343]]

之前用 Redux 比較多,一直聽(tīng)說(shuō) Mobx 能讓你體驗(yàn)到在 React 里面寫(xiě) Vue 的感覺(jué),今天打算嘗試下 Mobx 是不是真的有寫(xiě) Vue 的感覺(jué)。

題外話

在介紹 MobX 的用法之前,先說(shuō)點(diǎn)題外話,我們可以看一下 MobX 的中文簡(jiǎn)介。在 MobX 的中文網(wǎng)站上寫(xiě)著:

“MobX 是一個(gè)經(jīng)過(guò)戰(zhàn)火洗禮的庫(kù),它通過(guò)透明的函數(shù)響應(yīng)式編程使得狀態(tài)管理變得簡(jiǎn)單和可擴(kuò)展。

數(shù)據(jù)流

“戰(zhàn)火洗禮的庫(kù)” 怎么看都感覺(jué)很奇怪,讀起來(lái)很拗口??,而且網(wǎng)上很多介紹 MobX 的文章都是這么寫(xiě)的,在 github 翻閱其 README 發(fā)現(xiàn)寫(xiě)的是:

“MobX is a battle tested library that makes state management simple and scalable by transparently applying functional reactive programming (TFRP).

可以看到作者原本要表達(dá)的意思是 MobX 是經(jīng)過(guò)了許多的測(cè)試,擁有比較強(qiáng)的健壯性。下面是通過(guò)谷歌翻譯的結(jié)果,看起來(lái)也比中文網(wǎng)的表達(dá)要準(zhǔn)確一些。

谷歌翻譯

雖然,我的英文水平也很菜,還是會(huì)盡量看官方的文檔,這樣可以避免一些不必要的誤解。

如何使用?

言歸正傳,MobX 現(xiàn)在的最新版是 6.0,這個(gè)版本的 API 相比于之前有了極大的簡(jiǎn)化,可以說(shuō)更加好用了。之前的版本是裝飾器風(fēng)格的語(yǔ)法糖,但是裝飾器在現(xiàn)在的 ES 規(guī)范中并不成熟,而且引入裝飾器語(yǔ)法也在增加打包后的代碼體積。綜合考慮后,MobX 6.0 取消了裝飾器語(yǔ)法的 API。

響應(yīng)式對(duì)象

MobX 通過(guò) makeObservable 方法來(lái)構(gòu)造響應(yīng)式對(duì)象,傳入的對(duì)象屬性會(huì)通過(guò) Proxy 代理,與 Vue 類似,在 6.0 版本之前使用的是 Object.defineProperty API,當(dāng)然 6.0 也提供了降級(jí)方案。

  1. import { configure, makeObservable, observable, action, computed } from 'mobx' 
  2.  
  3. // 使用該配置,可以將 Proxy 降級(jí)為 Object.defineProperty 
  4. configure({ useProxies: "never" }); 
  5.  
  6. // 構(gòu)造響應(yīng)對(duì)象 
  7. const store = makeObservable( 
  8.   // 需要代理的響應(yīng)對(duì)象 
  9.   { 
  10.     count: 0, 
  11.     get double() { 
  12.       return this.count * 2 
  13.     }, 
  14.     increment() { 
  15.       this.count += 1 
  16.     }, 
  17.     decrement() { 
  18.       this.count -= 1 
  19.     } 
  20.   }, 
  21.   // 對(duì)各個(gè)屬性進(jìn)行包裝,用于標(biāo)記該屬性的作用 
  22.   { 
  23.     count: observable, // 需要跟蹤的響應(yīng)屬性 
  24.     double: computed,  // 計(jì)算屬性 
  25.     increment: action, // action 調(diào)用后,會(huì)修改響應(yīng)對(duì)象 
  26.     decrement: action, // action 調(diào)用后,會(huì)修改響應(yīng)對(duì)象 
  27.   } 

我們?cè)诳纯粗鞍姹镜?MobX,使用裝飾器的寫(xiě)法:

  1. class Store { 
  2.   @observable count = 0 
  3.   constructor() { 
  4.     makeObservable(this) 
  5.   } 
  6.   @action increment() { 
  7.     this.count++; 
  8.   } 
  9.   @action decrement() { 
  10.     this.count--; 
  11.   } 
  12.   @computed get double() { 
  13.     return this.count * 2 
  14.   } 
  15.  
  16. const store = new Store() 

這么看起來(lái),好像寫(xiě)法并沒(méi)有得到什么簡(jiǎn)化,好像比寫(xiě)裝飾器還要復(fù)雜點(diǎn)。下面我們看看 6.0 版本一個(gè)更強(qiáng)大的 API:makeAutoObservable。

makeAutoObservable 是一個(gè)更強(qiáng)大的 makeObservable,可以自動(dòng)為屬性加上對(duì)象的包裝函數(shù),上手成本直線下降。

  1. import { makeAutoObservable } from 'mobx' 
  2.  
  3. const store = makeAutoObservable({ 
  4.   count: 0, 
  5.   get double() { 
  6.     return this.count * 2 
  7.   }, 
  8.   increment() { 
  9.     this.count += 1 
  10.   }, 
  11.   decrement() { 
  12.     this.count -= 1 
  13.   } 
  14. }) 

計(jì)算屬性

MobX 的屬性與 Vue 的 computed 一樣,在 makeAutoObservable 中就是一個(gè) getter,getter 依賴的值一旦發(fā)生變化,getter 本身的返回值也會(huì)跟隨變化。

  1. import { makeAutoObservable } from 'mobx' 
  2.  
  3. const store = makeAutoObservable({ 
  4.   count: 0, 
  5.   get double() { 
  6.     return this.count * 2 
  7.   } 
  8. }) 

當(dāng) store.count 為 1 時(shí),調(diào)用 store.double 會(huì)返回 2。

修改行為

當(dāng)我們需要修改 store 上的響應(yīng)屬性時(shí),我們可以通過(guò)直接重新賦值的方式修改,但是這樣會(huì)得到 MobX 的警告??。

  1. const store = makeAutoObservable({ 
  2.   count: 0 
  3. }); 
  4.  
  5. document.getElementById("increment").onclick = function () { 
  6.   store.count += 1 

warn

MobX 會(huì)提示,在修改響應(yīng)式對(duì)象的屬性時(shí),需要通過(guò) action 的方式修改。雖然直接修改也能生效,但是這樣會(huì)讓 MobX 狀態(tài)的管理比較混亂,而且將狀態(tài)修改放到 action 中,能夠讓 MobX 在內(nèi)部的事務(wù)流程中進(jìn)行修改,以免拿到的某個(gè)屬性還處于中間態(tài),最后計(jì)算的結(jié)果不夠準(zhǔn)確。

makeAutoObservable 中的所有方法都會(huì)被處理成 action。

  1. import { makeAutoObservable } from 'mobx' 
  2.  
  3. const store = makeAutoObservable({ 
  4.   count: 0, 
  5.   get double() { 
  6.     return this.count * 2 
  7.   }, 
  8.   increment() { // action 
  9.     this.count += 1 
  10.   }, 
  11.   decrement() { // action 
  12.     this.count -= 1 
  13.   } 
  14. }) 

不同于 Vuex,將狀態(tài)的修改劃分為 mutation 和 action,同步修改放到 mutation 中,異步的操作放到 action 中。在 MobX 中,不管是同步還是異步操作,都可以放到 action 中,只是異步操作在修改屬性時(shí),需要將賦值操作放到 runInAction 中。

  1. import { runInAction, makeAutoObservable } from 'mobx' 
  2.  
  3. const store = makeAutoObservable({ 
  4.   count: 0, 
  5.   async initCount() { 
  6.     // 模擬獲取遠(yuǎn)程的數(shù)據(jù) 
  7.     const count = await new Promise((resolve) => { 
  8.       setTimeout(() => { 
  9.         resolve(10) 
  10.       }, 500) 
  11.     }) 
  12.     // 獲取數(shù)據(jù)后,將賦值操作放到 runInAction 中 
  13.     runInAction(() => { 
  14.       this.count = count 
  15.     }) 
  16.   } 
  17. }) 
  18.  
  19. store.initCount() 

如果不調(diào)用 runInAction ,則可以直接調(diào)用本身已經(jīng)存在的 action。

  1. import { runInAction, makeAutoObservable } from 'mobx' 
  2.  
  3. const store = makeAutoObservable({ 
  4.   count: 0, 
  5.   setCount(count) { 
  6.     this.count = count 
  7.   }, 
  8.   async initCount() { 
  9.     // 模擬獲取遠(yuǎn)程的數(shù)據(jù) 
  10.     const count = await new Promise((resolve) => { 
  11.       setTimeout(() => { 
  12.         resolve(10) 
  13.       }, 500) 
  14.     }) 
  15.     // 獲取數(shù)據(jù)后,調(diào)用已有的 action 
  16.     this.setCount(count
  17.   } 
  18. }) 
  19.  
  20. store.initCount() 

監(jiān)聽(tīng)對(duì)象變更

無(wú)論是在 React 還是在小程序中想要引入 MobX,都需要在對(duì)象變更的時(shí)候,通知調(diào)用原生的 setState/setData 方法,將狀態(tài)同步到視圖上。

通過(guò) autorun 方法可以實(shí)現(xiàn)這個(gè)能力,我們可以把 autorun 理解為 React Hooks 中的 useEffect。每當(dāng) store 的響應(yīng)屬性發(fā)生修改時(shí),傳入 autorun 的方法(effect)就會(huì)被調(diào)用一次。

  1. import { autorun, makeAutoObservable } from 'mobx' 
  2.  
  3. const store = makeAutoObservable({ 
  4.   count: 0, 
  5.   setCount(count) { 
  6.     this.count = count 
  7.   }, 
  8.   increment() { 
  9.     this.count++ 
  10.   }, 
  11.   decrement() { 
  12.     this.count-- 
  13.   } 
  14. }) 
  15.  
  16. document.getElementById("increment").onclick = function () { 
  17.   store.count++ 
  18.  
  19. const $count = document.getElementById("count"
  20. $count.innerText = `${store.count}` 
  21. autorun(() => { 
  22.   $count.innerText = `${store.count}` 
  23. }) 

每當(dāng) button#increment 按鈕被點(diǎn)擊的時(shí)候,span#count 內(nèi)的值就會(huì)自動(dòng)進(jìn)行同步。??查看完整代碼。

效果演示

除了 autorun ,MobX 還提供了更精細(xì)化的監(jiān)聽(tīng)方法:reaction、 when。

  1. const store = makeAutoObservable({ 
  2.   count: 0, 
  3.   setCount(count) { 
  4.     this.count = count 
  5.   }, 
  6.   increment() { 
  7.     this.count++ 
  8.   }, 
  9.   decrement() { 
  10.     this.count-- 
  11.   } 
  12. }) 
  13.  
  14. // store 發(fā)生修改立即調(diào)用 effect 
  15. autorun(() => { 
  16.   $count.innerText = `${store.count}` 
  17. }); 
  18.  
  19. // 第一個(gè)方法的返回值修改后才會(huì)調(diào)用后面的 effect 
  20. reaction( 
  21.   // 表示 store.count 修改后才會(huì)調(diào)用 
  22.   () => store.count
  23.   // 第一個(gè)參數(shù)為當(dāng)前值,第二個(gè)參數(shù)為修改前的值 
  24.   // 有點(diǎn)類似與 Vue 中的 watch 
  25.   (value, prevValue) => { 
  26.     console.log('diff', value - prevValue) 
  27.   } 
  28. ); 
  29.  
  30. // 第一個(gè)方法的返回值為真,立即調(diào)用后面的 effect 
  31. when(() => store.count > 10, () => { 
  32.   console.log(store.count
  33. }) 
  34. // when 方法還能返回一個(gè) promise 
  35. (async function() { 
  36.   await when(() => store.count > 10) 
  37.   console.log('store.count > 10'
  38. })() 

總結(jié)

MobX 的介紹到這里就結(jié)束了,本文只是大致的列舉了一下 MobX 的 API,希望大家能有所收獲。后續(xù)打算再深入研究下 MobX 的實(shí)現(xiàn),等我研究好了,再寫(xiě)篇文章來(lái)分享。

 

責(zé)任編輯:武曉燕 來(lái)源: 更了不起的前端
相關(guān)推薦

2014-06-24 09:41:56

Android Stu教程

2024-01-29 00:36:50

Backstage設(shè)施工具

2016-06-20 10:20:22

Docker云計(jì)算

2021-11-26 09:40:37

EclipseIDEA開(kāi)發(fā)

2014-01-22 10:00:10

Android SDKAndroid開(kāi)發(fā)

2013-12-04 13:27:56

Android SDK項(xiàng)目

2013-12-04 14:44:41

Android SDK用戶交互

2013-12-26 15:40:33

Android SDK項(xiàng)目

2014-06-06 14:25:03

iOS 8SwiftWWDC2014

2013-12-26 15:14:38

Android SDK運(yùn)行調(diào)試

2012-08-01 17:39:17

2013-12-26 14:52:52

Android SDK物理設(shè)備

2021-01-19 06:16:05

前端Babel 技術(shù)熱點(diǎn)

2013-11-27 10:12:11

2013-12-04 14:29:18

Android SDK應(yīng)用程序

2013-12-26 15:47:59

Android SDK應(yīng)用程序

2014-03-16 09:21:39

Android開(kāi)發(fā)Android SDK

2013-12-04 15:11:03

Android SDK應(yīng)用程序

2013-12-26 15:26:48

Android SDKActivity生命周期

2021-02-24 08:32:45

Web Compone前端Web 應(yīng)用
點(diǎn)贊
收藏

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