@medux 数据流

欢迎您开始 @medux 之旅,建议您依次阅读如下 4 篇文章,这将耗费您大约 30 分钟。javascript

第 4 篇:medux 数据流vue

-- Github 地址 ---java

@medux 数据流示意图

data-flow.png

基于 Redux

由于 Medux 基于 Redux,因此部分数据流与 Redux 很类似,好比:react

  • 保持全局单例的 Store
  • Store 和 View 之间使用单向数据流
  • 改变 Store 数据,必须经过 Reducer
  • 调用 Reducer 必须经过显式的 dispatch Action

模块化 Store

  • 每一个 module 仅能经过 reducer 修改 Store 下的某个一级子节点(moduleState),跨 module 不能直接修改
  • 每一个 module 能够读取全部 Store 的子节点
  • Store 一级子节点除了 moduleState 还能够是其它 ReduxReducers 管理的节点(好比 route),它们依然遵循以上原则

封装 Effect

  • 将全部反作用封装在 Effect 中执行
  • Effect 要修改 Store,必须从新 dispatch Action 经过 Reducer 来执行
  • Effect 能够经过 dispatch Action 来触执行另外一个 Effect
  • Effect 执行是异步的,可使用 await 来跟踪其执行结果,好比:
...
await this.dispatch(this.action.searchList());
this.dispatch(this.action.showPop());
复制代码

跟踪 Effect 的执行

你只需在定义 Effect 的装饰器中加入可控的参数既可注入其 loading 状态到 moduleState 中:git

// loadingForGroupName 注入加载状态的分组key,默认为global,若是为null表示不注入加载状态
// loadingForModuleName 可将loading状态合并注入到其余module,默认为入口主模块
function effect(loadingForGroupName?: string | null, loadingForModuleName?: string)

// 例如
@effect('global')
public async login(username:string, password:string){
  ...
}
复制代码

除了 loading 状态,你还能够直接编写 effect 执行先后的钩子:github

function logger(before: (action: Action, moduleName: string, promiseResult: Promise<any>) => void, after: null | ((status: 'Rejected' | 'Resolved', beforeResult: any, effectResult: any) => void));
复制代码

让 Action 具备 Event 性质

reducer 或 effect 咱们统称为 ActionHandler,当执行 store.dispatch(action)时,会触发一个目标 ActionHandler 的执行,咱们称之为主ActionHandler。除了主 ActionHandler,还能够存在一系列从ActionHandler来配合执行,它们能够属于不一样的 module,因此一般用来解决 module 之间的协做。web

从本文顶部的 medux 数据流示意图中看出,蓝色的 Action 彷佛像一条总线穿透各个 module,它的 Event 性质让整个模块变得松散起来typescript

ActionHandler 的执行顺序

一个 Action 被 dispatch 可能引发一系列 reducer 和 effect 执行,那么它们的执行顺序是怎样的呢?redux

  • 主ActionHandler老是先执行
  • 从ActionHandler默认是按注册顺序,可是你能够设置 Action.priority 来强制干预
  • reducer 是同步的,它们老是先执行
  • effect 是异步的,它们会并发执行,除非你使用 await
interface Action {
  type: string;
  priority?: string[]; //执行优先级
  payload?: any[];
}
复制代码

当 ActionHandler 执行出错时

当 actionHandler 执行出错时,medux 会自动 dispatch 一个 type 为medux.Error的新 Action,你能够 handler 这个 ErrorAction,并对错误进行处理:api

  • 若是在处理中继续 throw 错误,将再也不重复 dispatch ErrorAction,当前代码将中断执行
  • 不然被视为解决了错误,代码继续往下执行

View 和 Component

View 本质上就是一个 Component,可是 View 用来展现业务,Component 用来展现交互。从本文最开始的 Medux 数据流示意图中看出:

  • View 一般订阅了 Store,并从 Store 中之间得到数据。Component 则只能经过 props 来进行传递
  • View 必定属于某个 Module。Component 能够属于某个 Module 专用,也能够属于所有 Module
  • View 和 Component 之间能够相互嵌套
  • View 和 View 之间也能够相互嵌套,可是不能直接经过 import 另外一个 view,必须经过 loadView 方法加载
const RoleSelector = loadView('adminRole', 'Selector');
复制代码

关于 RouteState

框架会自动监听路由的变化,并将路由信息解析为 RouteState,而后:

  • 经过dispatch medux.RouteChangeAction 将其注入 Redux 一级子节点 route 中
  • 经过dispatch moduleName.RouteParamsAction 将其注入相应的 moduleState
  • 你能够监听以上 2 个 action 来作一些事情

使用 MutableData 可变数据

喜欢 vue 或 mobx 的朋友可能会问,medux 是要求可变数据仍是不可变数据?

虽然 medux 是基于 redux 的,但本着实用至上的原则,并不要求严格遵循 redux 模型,它是另外一个 flux 框架。

medux 框架内部会使用 ImmutableData 来自动生成并管理 state 及其 1 级节点,对于这个内置数据结构一般你也无需干预。而对于次级的 moduleState 你能够将它定义为 一个 MutableData,而后直接在 reducer 中修改 state 并返回它,尽管这有违 reducer 的本意,但这是对接 MutableData 最简单灵活的方案。

CoreAPI

查看 CoreAPI 文档

web+medux+react

@medux/react-web-router:整合封装了@medux/core、@medux/web、@medux/route-plan-a、@medux/react, 是 web 环境下开发 react 的开箱即用框架

Demo

medux-react-admin:基于@medux/react-web-router和最新的ANTD 4.x开发的通用后台管理系统,除了演示 medux 怎么使用,它还创造了很多独特的理念

相关文章
相关标签/搜索