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

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

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

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

特征

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

从依赖追踪开始

dob 本身只实现了依赖追踪功能,其特性很是简单,以下示意图+代码所示:java

imgimg

import { observable, observe } from "dob"

const obj = observable({ a: 1, b: 1 })

observe(() => {
    console.log(obj.a)
})

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

与 react 优雅结合

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

imgimg

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 作的工做。github

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

全局数据流

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

imgimg

因为聚合 store 注入到 react 很是简单,只须要 Provider @Connect 便可,因此组织好 store 与 action 的关系,也就组织好了整个应用结构。框架

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

imgimg

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

结构以下图所示:

imgimg

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-devtoolsdob-react-devtools

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


更多专业前端知识,请上 【猿2048】www.mk2048.com
相关文章
相关标签/搜索