基於Redux/Vuex/MobX等庫的通用化狀態OOP

architecture

若是你對Redux/Mobx/Vuex等狀態庫如何更好的OOP設計感興趣,那麼本文將給出一個前端狀態庫OOP完整的通用化方案。前端

動機

因爲前端單頁應用開發日趨複雜,當咱們在使用React/Vue時,爲了開發複雜的App讓咱們不得不用到一些狀態管理或者狀態容器(下文統稱爲狀態庫),同時咱們也須要一個更容易模塊化的模型。vue

前端狀態庫百花齊放,不管是Redux/MobX/Vuex以及Angular自帶的狀態管理,狀態庫的模塊化也一直是最近幾年複雜系統中的前端開發領域的新需求。Redux是具備不可變數據結構的可預測狀態容器。MobX是一種可觀察的狀態管理庫。Vuex是在Vue中具備可觀察的集中狀態管理庫。而對於模塊化而言, Angular已經有了本身的實現, 但對其餘狀態管理庫倒是愈來愈須要在複雜的前端項目中處理這一新的要求。react

在本文中, 讓咱們探索一種新的OOP模塊化設計, 該模塊化設計對主流的狀態管理庫都具備廣泛性支持。git

通用化狀態模塊

一般狀況下,前端中大型項目的架構設計中常見於採用面向對象編程(OOP),在決定狀態管理庫時, 常常會提出如下問題:github

  • 究竟是Redux仍是MobX更適用於React?
  • Redux適合應用於OOP嗎?
  • MobX的observable在React帶來利弊如何權衡?
  • 在Vue中Vuex如何OOP?

此外,大部分狀況下,前端架構與狀態管理緊密耦合。一旦選擇了狀態管理庫, 就很難在沒有重大重構的狀況下切換到另外一個庫。所以, 任何使用該架構的系統也必須使用相同的狀態庫。但更好的前端架構設計應該是靈活和可擴展。特別是對於旨在實現集成目的的設計, 以適應目標環境和SDK架構則很是重要。爲了建立與z主流框架 (React+Redux/React+MobX/Vue+Vuex/Angular) 配合使用的模塊, 咱們須要通用化狀態模塊設計。vuex

設計目標

  • 基於Redux/MobX/Vuex 等狀態庫的OOP的設計,這也是最重要的,尤爲對Vue和React而言。
  • 被封裝的OOP設計是否足夠簡單易用,同時它們具備至關靈活性。
  • 從DDD角度說,在複雜的domain modules間的依賴關係須要IoC,它們之間的啓動邏輯有依賴關係,那麼必然有相似事件機制或者module生命週期的引入。

爲解決以上幾個問題,通用化OOP封裝和模塊標準化生命週期或者事件機制變得不可或缺。編程

提出解決方案

基於這樣通用化的概念,咱們提出新的通用化狀態模塊的庫 —— usmredux

首先,它應該能解決是基於Redux/MobX/Vuex等狀態庫的OOP設計。數據結構

讓咱們從典型的Redux計數器示例開始:架構

import { createStore } from 'redux';

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

const store = createStore(counter)

store.dispatch({ type: 'INCREMENT' })
store.dispatch({ type: 'DECREMENT' })
複製代碼

USM支持Redux、MobX、Vuex和Angular。它提供了usmusm-reduxusm-mobxusm-vuex四個子包。下面是使用usm-redux的計數器例子:

import Module, { state, action } from 'usm-redux';

class Counter extends Module {
  @state count = 0;

  @action
  increase(state) {
    state.count += 1;
  }

  @action
  decrease(state) {
    state.count -= 1;
  }
}

const counter = Counter.create();

counter.increase();
counter.decrease();
複製代碼

上面相同計數器的實現基於面向對象的範式。ES6類語法的使用直觀而簡潔。若是這種設計能夠通用於任何使用的狀態管理庫, 無疑將爲開發人員帶來更靈活、更友好的開發體驗, 以及更好的可讀性和可維護性。

在本示例中使用了usm-redux, 它基於Immer實現了從mutable操做獲得immutable數據。

我必須認可Redux在immutable類型的狀態庫中絕對是最好的庫之一,在這裏我無心要討論一些Redux的缺點,咱們想探討的是如何利用Redux進行更好的OOP設計。咱們但願基於Redux的模型能夠更加直觀和簡潔,就像上面提到的基於ES6+的class的Counter的OO例子同樣,若是這樣的OO範式它同時仍是通用化的狀態模型,一個更好的統一狀態庫封裝, 這無疑能夠給開發者帶來會有一種更靈活和更友好的編程體驗(固然也包括易於閱讀/維護等)。usm正好解決了這些問題。

下面演示在React中如何使用react-reduxusm-redux鏈接:

// index.js
export const counter = Counter.create();

ReactDOM.render(
  <Provider store={counter.store}> <App /> </Provider>,
  document.getElementById('root')
);
複製代碼
// app.js
import { connect } from 'react-redux';
import { counter } from './';

export default connect(
  state => ({ count: state.count })
)( props => 
  <div>
    <button onClick={() => counter.increase()}>+</button>
    {props.count}
    <button onClick={() => counter.decrease()}>-</button>
  </div>
);
複製代碼

下面是使用mobx-reactusm-mobx的鏈接例子:

// index.js

export const counter = Counter.create();

ReactDOM.render(
  <App />, document.getElementById('root') ); 複製代碼
// app.js
import { observer } from 'mobx-react';
import { counter } from './';

export default observer(() =>
  <div>
    <button onClick={() => counter.increase()}>+</button>
    {counter.count}
    <button onClick={() => counter.decrease()}>-</button>
  </div>
);
複製代碼

使用usm-redux+react-reduxusm-mobx+react-redux與React的結合例子足以證實, 即便使用的鏈接器不一樣, 但狀態模塊的核心業務邏輯是相同的。這是咱們提出的通用化狀態模塊的核心原則。

USM 目前支持Redux, MobX, Vuex和Angular。

特性

  • 通用化狀態模塊
  • 標準化模塊生命週期
  • 可選事件系統
  • 支持無狀態最小化模型
  • 支持Redux/MobX/Vuex/Angular

裝飾器

usm提供@state用於包裝一個帶狀態的變量,@action用於包裝一個改變狀態的函數(函數傳入的最後一個參數均爲當前state對象),除此之外和一個普通的class封裝的OO模塊沒有區別, usm同時也提供了通用的@computed

class Shop extends Module {
  @state goods = [];
  @state status = 'close';

  @action
  operate(item, status, state) {
    state.goods.push(item);
    state.status = status;
  }
  //this.operate({ name: 'fruits', amount: 10 }, 'open');
}
複製代碼

模塊生命週期

usm提供五個支持異步的生命週期函數:

  • moduleWillInitialize
  • moduleWillInitializeSuccess
  • moduleDidInitialize
  • moduleWillReset
  • moduleDidReset

它們的運行順序以下圖所示:

lifecycle

須要特別說明的,usm之因此提供生命週期是由於在大部分複雜的領域模塊間場景下,這些模塊生命週期可用於協調模塊初始化時的依賴關係。 固然,在沒必要使用它們的時候,它們的設置都是能夠省缺的。

理想中的架構設計

flow chart

在複雜前端模塊系統中, 這也許是一個比較典型的模塊化架構設計,它包含如下幾個部分:

  • 生命週期
  • Store訂閱器
  • 事件系統
  • State
  • 依賴模塊
  • 領域模型

在這裏只是提出這樣的設想,或許某些架構運用場景下多是這樣設計模型的擴充或刪減。

結論

USM是一種模塊設計, 它但願將在不一樣視圖層 (如React、Vue和Angular) 的組合中使用Redux、MobX和Vuex的差別聯繫在一塊兒。它旨在幫助您構建可用於任何前端架構的庫。

而當你使用React+Redux/React+MobX/Vue+Vuex等庫或者框架組合進行開發時,但願usm是在你的應用系統模塊化不錯的選擇,尤爲它多是你在使用React/Vue等UI構建庫時缺乏的那塊重要的模塊化拼圖。

換句話說,若是你使用usm進行OOP架構設計,那麼你的系統不只能夠減小不一樣狀態庫的boilerplate,尤爲像Redux這樣boilerplate較多的庫而樣應該有很大的幫助。最重要的是,usm可讓你須要的OOP架構的模塊化變得簡潔而直觀,甚至usm可讓你的業務代碼兼容各類狀態庫,不管是Redux/MobX/Vuex仍是Angular,並且若是你用的UI組件庫正好也兼容React/Vue/Angular,那麼你的應用將快速無縫使用React/Vue/Angular。

USM容許您跨框架共享業務邏輯庫, 而無需考慮它們所使用的框架。

最後,咱們或許提出一個值得思考的問題:

從OOP角度來講,前端狀態庫的選擇真的那麼那麼的重要嗎?

相關文章
相關標籤/搜索