React狀態管理大亂鬥,橫向對比Dva,Rematch,Mirror

這年頭,Redux 狀態管理框架滿天飛,前幾天在網上閒逛偶然又發現 Rematch、Mirror、Smox、Xredux,都用了一下,發現都是套瓷娃娃,大同小異,拿幾個比較歷害的來講:react

無非就是相似這樣的:webpack

model({
    state: ...,
    reducers: {
        aaa(playload)
        bbb(playload)
    },
    effects: {
        ccc(playload)
        ddd(playload)
    }
})
複製代碼

無聊

審美疲勞了?H 起來,給你們推薦一款小鮮肉React-coatgit

項目地址:github.com/wooline/rea…github

class ModuleHandlers extends BaseModuleHandlers {
  @reducer
  public aaa(playload): State {...}

  @reducer
  private bbb(playload): State {...}

  @effect("ajaxLoading")
  public async ccc(playload) {...}

  @effect("loginLoading")
  private async ddd(playload) {...}
}
複製代碼

spring 風格?ng 風格?web

小鮮肉

可能你會說,用 Class 呀,不喜歡,我喜歡 FP 風格。我想說,這是狀態管理框架非 React UI 框架,不要爲了流行 FP 就皆 FP,就象當年 JS 流行面向對象編程,把面向過程說成洪水猛獸。ajax

武裝到牙齒的 TS 類型反射

React-coat 全面擁抱 Typescript,直接上圖:spring

action 調用時的類型反射:編程

動態加載模塊時的類型反射:json

Store State 結構的類型反射:redux

連路由參數也有類型反射:

小鮮肉

支持單頁 SPA 和服務器渲染 SSR 同構

  • 並且SSR 在開發時也能夠享受:「熱更新」
  • 還支持 SPA(單頁) + SSR(服務器渲染)一鍵切換。

打開項目根下的./package.json,在"devServer"項中,將 ssr 設爲 true 將啓用服務器渲染,設爲 false 僅使用瀏覽器渲染

關於服務器渲染SSR請移步另外一篇文章:juejin.im/post/5c7f6e…

小鮮肉

強大而便捷的 Dispatch Action

對比一下各大框架 Dispatch Action 的語法:

// Dva中
yield put({type: 'moduleA/increment',  payload: 2});

// Rematch中
dispatch.moduleA.increment(2);

// Mirror中
actions.moduleA.increment(2);

// React-coat中
import moduleA from "modules/moduleA/facade";
...
await this.dispatch(moduleA.actions.increment(2));
複製代碼
  • 語法簡潔性上,Dva 用的 saga 中的 yield put,還要寫 type 和 payload,最繁瑣。其它三款都直接用方法調用,更簡潔。

  • Rematch 和 Mirror 等於把全部 action 都放到一個全局變量中去了,而 React-coat 去中心化,按需引入 moduleA,更利於系統保持鬆散結構

  • 從語義上來講 React-coat 依然顯示的保留 dispatch 關鍵字,moduleA.actions.increment(2) 返回的是依然是 Action,dispatch(action) 做爲 Redux 的基本理念獲得完整的保持,Rematch 和 Mirror 已經變成傳統的 MVC 了。

  • 從功能上,只有 Dva 和 React 支持同步 effect。其它兩款都不支持,或者是我沒發現?什麼是同步 effect?例如:

    • query 會觸發一個 effect,updateState 會觸發一個 reducer
    • updateState 須要等待 query 執行完後再 dispatch
    // Dva中使用 saga 的 put.resolve 來支持同步 effect
    yield put.resolve({type: 'query',payload:1});
    yield put({type: 'updateState',  payload: 2});
    複製代碼
    // React-coat 中能夠直接 awiat dispatch
    await this.dispatch(thisModule.actions.query(1));
    this.dispatch(thisModule.actions.updateState(2));
    複製代碼
  • React-coat 的獨有的殺手鐗:action 名稱和參數的類型反射和智能提示、public private 權限的控制,讓你感覺什麼才叫真正的封裝。試想下若是多人同時並行開發多個模塊,你還須要爲你的模塊寫一大篇 API 說明文檔麼?

小鮮肉

完全的模塊化

既然是企業級應用,那模塊化天然是少不了的,包括模塊封裝、代碼分割、按需加載。模塊化的目的主要是拆分複雜系統、解耦與重用。

以上框架中,Rematch 和 Mirror 的模塊化功能比較弱,且不優雅,略過。Dva 和 React-coat 都有強大的模塊化功能,其中 Dva 能夠搭配 UMI 來自動配置。

在 dva 中動態加載 model 和 component,要靠路由配置:

{
  path: '/user',
  models: () => [import(/* webpackChunkName: 'userModel' */'./pages/users/model.js')],
  component: () => import(/* webpackChunkName: 'userPage' */'./pages/users/page.js'),
}
複製代碼

React-coat 中代碼分割和路由分層而治:

  • 代碼分割只作代碼分割,不參和路由的事,由於模塊也不必定是非得用路由的方式來加載。
  • 路由只作路由的事情,不參和代碼分割的事,由於模塊也不必定非得作代碼分割。
  • 一個 Module 總體打包成一個 bundle,包括 model 和 views,不至於太碎片。
// 定義代碼分割
export const moduleGetter = {
  app: () => {
    return import(/* webpackChunkName: "app" */ "modules/app");
  },
  photos: () => {
    return import(/* webpackChunkName: "photos" */ "modules/photos");
  },
}
複製代碼

React-coat 中支持路由動態加載,也支持非路由動態加載

// 使用路由加載:
const PhotosView = loadView(moduleGetter, ModuleNames.photos, "Main");
...
<Route exact={false} path="/photos" component={PhotosView} />
複製代碼
// 直接加載:
const PhotosView = loadView(moduleGetter, ModuleNames.photos, "Main");
...
render() {
  const {showDetails} = this.props;
  return showDetails ? <DetailsView /> : <ListView />; } 複製代碼
  • Dva 以 Page UI 主線來劃分模塊;React-coat 以業務功能高內聚、低偶合來劃分模塊。後者更適合解耦與重用。
  • Dva 使用集中配置、將 Page、路由、model、代碼分割所有都集中寫在一箇中心文件中;React-coat 去中心化,將各自的邏輯封裝在各自模塊中,而且 model、代碼分割、路由分層而治,互不干涉。後者更乾淨整潔。
  • Dva 將每一個 model 和 component 都作成一個代碼分割包;React-coat 將一個 Module 總體作成一個代碼分割包,前者太碎,後者更符合 bundle 概念。
  • React-coat 支持路由動態加載 View,也支持非路由動態加載 View,二條腿走路步子邁得更大。
  • React-coat 動態加載 View 時會自動導入 Model,無需手工配置加載 Model,是真正的路由組件化。

更多差別仍是請看:與 DvaJS 風雲對話,是 DvaJS 挑戰者?仍是又一輪子?

小鮮肉

跨模塊的調用與協做

在複雜的長業務流程中,跨模塊調用與協做是少不了的,Dva、Rematch、Mirror、React-coat 都支持跨模塊派發 action,跨模塊讀取 State。好比:

// Mirror中
if(resphonse.success){
    actions.moduleA.doSomeEffect();
    actions.moduleB.doSomeEffect();
}
複製代碼

這是一種串聯調用的模式,適應於一些耦合緊密的業務流。 但對於一些鬆散耦合的業務流程,最佳的方式應當是觀察者模式,或叫事件廣播模式。

場景:當 moduleA 執行了一個 action,moduleB、moduleC、moduleD...都須要執行一些各自的動做

這就是 React-coat 獨有的殺手鐗:ActionHandler 概念。

class ModuleB {
    //在ModuleB中監聽"ModuleA/update" action
    async ["ModuleA/update"] (){
        await this.dispatch(this.action.featchData())
    }
}

class ModuleC {
    //在ModuleC中監聽"ModuleA/update" action
    async ["ModuleA/update"] (){
        await this.dispatch(this.action.featchData())
    }
}
複製代碼

React-coat 主動調用、事件廣播兩種模式都支持,二手都要抓,二手都要硬。就問你騷氣不騷氣?😂

相關文章
相關標籤/搜索