Redux與mobx對比我們應該如何選擇?


Redux 和 Mobx 都是當下比較火熱的數據流模型,一個背靠函數式,似乎成為了開源界標配,一個基於面向對象,低調的前行。


以下內容會嚴格遵循下面三個觀點:

目的一致

都是狀態管理庫,用來管理應用的內部狀態

受眾大體一致

一般都會被用到react中,雖然說這並不是必須的,你當然也可以用到vue或者angular里,但是,大多數情況下,都不會這么做

可相互替代

在項目之初,你可以選擇二者之一來滿足你的項目需求,但是到某一天你突然覺得另一個更和你氣味相投,你完全可以花點時間遷移過去,你會發現,它似乎也能滿足你的那些需求

學習難度對比:

mobX的學習中,你可以聽信關於30分鍾快速入門的神話,因為它真的很簡單,並且在這三十分鍾過去之后,你唯一需要花的時間就是偶爾翻翻文檔就可以自如的使用它了。

redux的入門學習也沒那么難,即使有些概念顯得比較抽象,你最多需要多花上半個小時就可以掌握它們了,但是當你真的去使用的時候,你會發現這一切原來並非想象的那么簡單,你不得不花更多的時間來學習更多:

當你需要異步的時候,你不得不考慮redux-thunk,你怎么可能不需要異步想用Promise,沒問題,先看看redux-promise-middleware怎么樣想搞個日志之類的東西,redux-logger已經准備好了。

工作量對比(以下代碼直接在nodejs環境下測試):

一般來講,這里應該用一個couter之類的示例來做
 
 const { createStore } = require('redux')
  const ADD = 'ADD'
  const initState = {count: 0}
  // reducer
  function counter(state = initState, action) {
    switch(action.type) {
      case ADD:
        return {...state, count: state.count + action.payload.count}
      default:
        return state
    }
  }
  // actions
  const AddOne = () => ({type: ADD, payload: {count:1}})
  // store
  const store = createStore(counter)
  store.subscribe(() => console.log(store.getState()))
  setInterval(() => store.dispatch(AddOne()), 1000)
不算注釋,大約15行左右,那么,mobx想要具備壓倒性的優勢,應該極力控制自己的大小才對

一個mobx的counter大概得長成這樣吧
  
const { observable, autorun } = require('mobx')
  const appState = observable({
    counter: 0,
    add(value){this.counter += value}
  })
  autorun(() => console.log(appState.counter))
  setInterval(() => appState.add(1), 1000)
好像只用了7行,約莫是redux實現的一半大

我的天哪,多出了那么多行代碼,我還要不要下班了

內存開銷對比:

大小只是浮於表面的東西,對於應用更友好的東西,才是核心的要點

在寫redux的action的時候,總是需要用到擴展語句或者Object.assign()的方式來得到一個新的state,這一點對於JavaScript而言是對象的淺拷貝,它對內存的開銷肯定是大於mobX中那樣直接操作對象屬性的方式大得多。

這一點比較6,算是一個可被重視的問題

以上內容黑得主角很明顯是屬於redux的,那,萬一我們換個視角看看呢

狀態管理的集中性:

mobX中竟然有這樣的寫法:

  const {observable} = require('mobx')
  const appState = observable({ counter: 0 })
  appState.counter += 1

直接修改狀態?這和react的理論完全相悖啊,還怎么和react搭配使用啊,我的狀態萬一被同事給悄悄改了可是會引發一場戰爭的啊,還是開啟嚴格模式吧。
你說redux做的怎么樣?試試不通過action更新一下state,當然不能成功啊。

樣板代碼的必要性:

關於樣板代碼,就要追溯到redux的基本設計選擇了,redux三大原則:

單一數據源
State 是只讀的
使用純函數來執行修改

所以可以說是這些樣本代碼保證了state的狀態的可管理性,畢竟所有的東西都是涇渭分明的,讓出錯的可能性和找問題的成本降到了最低。

以上,使用mobX入門簡單,構建應用迅速,但是當項目足夠大的時候,還是使用redux,如果的確對mobX愛不釋手,那還是開啟嚴格模式,再加上一套狀態管理的規范吧。

函數式 vs 面向對象

首先任何避開業務場景的技術選型都是耍流氓,我先耍一下流氓,首先函數式的優勢,比如:

無副作用,可時間回溯,適合並發。
數據流變換處理很拿手,比如 rxjs。
對於復雜數據邏輯、科學計算維的開發和維護效率更高。
當然,連原子都是由帶正電的原子核,與帶負電的電子組成的,幾乎任何事務都沒有絕對的好壞,面向對象也存在很多優勢,比如:

javascript 的鴨子類型,表明它基於對象,不適合完全函數式表達。
數學思維和數據處理適合用函數式,技術是為業務服務的,而業務模型適合用面向對象。
業務開發和做研究不同,邏輯嚴謹的函數式相當完美,但別指望每個程序員都願意消耗大量腦細胞解決日常業務問題。

Redux vs Mobx

那么具體到這兩種模型,又有一些特定的優缺點呈現出來。

Redux:

數據流流動很自然,因為任何 dispatch 都會導致廣播,需要依據對象引用是否變化來控制更新粒度。
如果充分利用時間回溯的特征,可以增強業務的可預測性與錯誤定位能力。
時間回溯代價很高,因為每次都要更新引用,除非增加代碼復雜度,或使用 immutable。
時間回溯的另一個代價是 action 與 reducer 完全脫節,數據流過程需要自行腦補。原因是可回溯必然不能保證引用關系。
引入中間件,其實主要為了解決異步帶來的副作用,業務邏輯或多或少參雜着 magic。
但是靈活利用中間件,可以通過約定完成許多復雜的工作。
對 typescript 支持困難。

Mobx:

數據流流動不自然,只有用到的數據才會引發綁定,局部精確更新,但免去了粒度控制煩惱。
沒有時間回溯能力,因為數據只有一份引用。
自始至終一份引用,不需要 immutable,也沒有復制對象的額外開銷。
沒有這樣的煩惱,數據流動由函數調用一氣呵成,便於調試。
業務開發不是腦力活,而是體力活,少一些 magic,多一些效率。
由於沒有 magic,所以沒有中間件機制,沒法通過 magic 加快工作效率(這里 magic 是指 action 分發到 reducer 的過程)。
完美支持 typescript。

到底如何選擇

一般前端數據流不太復雜的情況,使用 Mobx,因為更加清晰,也便於維護;如果大型項目建議使用redux


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM