面向未来的前端数据流框架 - dob

百般思念 提交于 2019-11-30 14:44:55

我们大部分对内产品,都广泛使用了 dob 管理前端数据流,下面隆重介绍一下。

dob 是利用 proxy 实现的数据依赖追踪工具,利用 dob-react 与 react 结合。

dob 的核心思想大量借鉴了 mobx,但是从实现原理、使用便捷性,以及调试工具都做了大量优化。

特征

  • ✅ 支持
  • ❌ 不支持
  • 📦 生态支持
  • 🤷 不完全支持
功能 redux mobx dob
异步 📦redux-thunk
可回溯 📦 mst
分形 🤷 replaceReducer
代码精简 📦 dva
函数式 🤷 🤷
面向对象 🤷
Typescript 支持 🤷
调试工具
调试工具 action 与 UI 双向绑定 🤷
严格模式
支持原生 Map 等类型
observable 语法自然度
store 规范化 🤷

从依赖追踪开始

dob 自己只实现了依赖追踪功能,其特性非常简单,如下示意图+代码所示:

img

import { observable, observe } from "dob"  const obj = observable({ a: 1, b: 1 })  observe(() => {     console.log(obj.a) })

一句话描述就是:由 observable 产生的对象,在 observe 回调函数中使用,当这个对象被修改时,会重新执行这个回调函数。

与 react 优雅结合

那么利用这个特性,将 observe 换成 react 框架的 render 函数,就变成了下图:

img

import { observable, observe } from "dob" import { Provider, Connect } from 'dob-react'  const obj = observable({ a: 1 })  @Connect class App extends React.Component {     render() {         return (             <span onClick={() => { this.props.store.a = 2 }}>                 {this.props.store.a}             </span>         )     } }  ReactDOM.render(     <Provider store={obj}> <App/> </Provider> , dom)

这正是 dob-react 做的工作。

上面这种结合随意性太强,不利于项目维护,真正的 dob-react 对 dob 的使用方式做了限制。

全局数据流

为了更好管理全局数据流,我们引入 action、store 的概念,组件只能触发 action,只有 action 内部才能修改 store:

img

由于聚合 store 注入到 react 非常简单,只需要 Provider @Connect 即可,所以组织好 store 与 action 的关系,也就组织好了整个应用结构。

那么如何组织 action、store、react 之间的关系呢?对全局数据流,dob 提供了一种成熟的模式:依赖注入。以下是可维护性良好模式

img

import { Action, observable, combineStores, inject } from 'dob' import { Provider, Connect } from 'dob-react'  @observable export class UserStore {     name = 'bob' }  export class UserAction {     @inject(UserStore) private UserStore: UserStore;      @Action setName () {         this.store.name = 'lucy'     } }  @Connect class App extends React.Component {     render() {         return (             <span onClick={this.props.UserAction.setName}>                 {this.props.UserStore.name}             </span>         )     } }  ReactDOM.render(     <Provider {         ...combineStores({             UserStore,             UserAction         })     }>         <App />     </Provider> , dom)

一句话描述就是:通过 combineStores 聚合 store 与 action,store 通过 inject 注入到 action 中被修改,react 组件通过 @Connect 自动注入聚合 store。

局部数据流

对于对全局状态不敏感的数据,可以作为局部数据流处理。

@Connect 装饰器如果不带参数,会给组件注入 Provider 所有参数,如果参数是一个对象,除了注入全局数据流,还会把这个对象注入到当前组件,由此实现了局部数据流。

PS: Connect 函数更多用法可以参考文档: dob-react #Connect

结构如下图所示:

img

import { Action, observable, combineStores, inject } from 'dob' import { Provider, Connect } from 'dob-react'  @observable export class UserStore {     name = 'bob' }  export class UserAction {     @inject(UserStore) private UserStore: UserStore;      @Action setName () {         this.store.name = 'lucy'     } }  @Connect(combineStores(UserStore, UserAction)) class App extends React.Component {     render() {         return (             <span onClick={this.props.UserAction.setName}>                 {this.props.UserStore.name}             </span>         )     } }

PS: 局部数据流可以替代 setState 管理组件自身状态,每当组件被实例化一次,就会创建一个与之绑定的局部数据流。如果不想使用 react 提供的 setState,可以使用局部数据流替代。

异步 & 副作用

redux 中需要将副作用代码从 reducer 抽离,而 dob 不需要,我们可以如下书写 action:

@Action async getUserInfo() {     this.UserStore.loading = true     this.UserStore.currentUser = await fetchUser()     this.UserStore.loading = false      try {         this.UserStore.articles = await fetchArticle()     } catch(error) {         // 静默失败     } }

Devtools

借助 dob-react-devtools 开启调试模式,可以实现类似 redux-devtools 的效果,但,该调试工具具备 action 与 UI 双向可视化绑定 的功能等:

  • UI 与 action 绑定:ui 元素触发 rerender 时,自身会高亮,并在左上角显示渲染次数,以及导致其 render 的 action。
  • action 与 UI 绑定:展开右侧 action 列表后,通过 hover 可展示因此 action 触发而 rerender 的 UI 元素,高亮出来。
  • 搜索、清空等方式管理 action。
  • 点击灯泡 开启/关闭 debug 模式。

假设现在有一个文章列表需求,我们创建了 ArticleStoreArticleActionArticleAction 提供了 addArticle, removeArticle, changeArticleTitle 等基础方法。

现在我们开启了调试功能,获得如下 gif 图的效果:

dob-react-devtools

dob-react-devtools 主要提供了可视化界面展示每个 Action 触发列表,鼠标移动到每个 Action 会高亮对应 rerender 的 UI 元素,UI 元素 render 的时候,左上角工具条也列出了与这个 UI 元素相关的 Action 列表。


更多专业前端知识,请上 【猿2048】www.mk2048.com
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!