基于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角度来讲,前端状态库的选择真的那么那么的重要吗?

相关文章
相关标签/搜索