react 的数据管理方案:redux 还是 mobx?

本文作者:IMWeb jerytang 原文出处:IMWeb社区 未经同意,禁止转载

mobx 简介

和 redux 类似,mobx 是一个数据管理库,都可以和 react 配合使用。它区别于 redux 的最大特点是,可以直接修改数据,对 UI 进行精确刷新。精确更新是什么意思呢,看下面的例子。

import { observable } from 'mobx';

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

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

obj.b = 3 // 什么都没有发生
obj.a = 2 // observe 函数的回调触发了,控制台输出:2
  • autoRun 中的函数对 a 进行了取值 get 操作,obj.a 和所在的函数完成了绑定关系;
  • 直接对 obj.a 进行赋值 set 操作,触发了 get 操作所在的函数执行;
  • 对 b 的操作没有触发——mobx 是精确到字段更新

将 mobx 的数据管理能力应用到 react 中: React Component 对数据源字段进行精确响应更新。

mobx 的更多介绍,移步mobxjs官网

这里直接上实际例子。

mobx 的例子是辅导题库项目中实践方案的简化演示。

实际例子:mobx 和 redux 对比

实现一个计数器增加、减少的功能。

如果直接使用 setState 也很容易实现这个功能。但是,这里分别用redux方案 和 mobx方案 实现上面的功能。

为了演示方便,将所有的代码都放在一个文件中。查看 mobx 实现的代码前,先了解下装饰器(decorator)是什么

redux 方案代码

import React, { Component } from 'react';
import {
  createStore,
  bindActionCreators,
} from 'redux';
import { Provider, connect } from 'react-redux';

// ①action types
const COUNTER_ADD = 'counter_add';
const COUNTER_DEC = 'counter_dec';

const initialState = {a: 0};
// ②reducers
function reducers(state = initialState, action) {
  switch (action.type) {
  case COUNTER_ADD:
    return {...state, a: state.a+1};
  case COUNTER_DEC:
    return {...state, a: state.a-1};
  default:
    return state
  }
}

// ③action creator
const incA = () => ({ type: COUNTER_ADD });
const decA = () => ({ type: COUNTER_DEC });
const Actions = {incA, decA};

class Demo extends Component {
  render() {
    const { store, actions } = this.props;
    return (
      <div>
        <p>a = {store.a}</p>
        <p>
          <button className="ui-btn" onClick={actions.incA}>增加 a</button>
          <button className="ui-btn" onClick={actions.decA}>减少 a</button>
        </p>
      </div>
    );
  }
}

// ④将state、actions 映射到组件 props
const mapStateToProps = state => ({store: state});
const mapDispatchToProps = dispatch => ({
  // ⑤bindActionCreators 简化 dispatch
  actions: bindActionCreators(Actions, dispatch)
})
// ⑥connect产生容器组件
const Root = connect(
  mapStateToProps,
  mapDispatchToProps
)(Demo)

const store = createStore(reducers)
export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <Root />
      </Provider>
    )
  }
}

mobx 方案代码

import React, { Component } from 'react';
import { observable, action } from 'mobx';
import { Provider, observer, inject } from 'mobx-react';

// 定义数据结构
class Store {
  // ① 使用 observable decorator 
  @observable a = 0;
}

// 定义对数据的操作
class Actions {
  constructor({store}) {
    this.store = store;
  }
  // ② 使用 action decorator 
  @action
  incA = () => {
    this.store.a++;
  }
  @action
  decA = () => {
    this.store.a--;
  }
}

// ③实例化单一数据源
const store = new Store();
// ④实例化 actions,并且和 store 进行关联
const actions = new Actions({store});

// inject 向业务组件注入 store,actions,和 Provider 配合使用
// ⑤ 使用 inject decorator 和 observer decorator
@inject('store', 'actions')
@observer
class Demo extends Component {
  render() {
    const { store, actions } = this.props;
    return (
      <div>
        <p>a = {store.a}</p>
        <p>
          <button className="ui-btn" onClick={actions.incA}>增加 a</button>
          <button className="ui-btn" onClick={actions.decA}>减少 a</button>
        </p>
      </div>
    );
  }
}

class App extends Component {
  render() {
    // ⑥使用Provider 在被 inject 的子组件里,可以通过 props.store props.actions 访问
    return (
      <Provider store={store} actions={actions}>
        <Demo />
      </Provider>
    )
  }
}

export default App;

使用 mobx 时,借鉴了 redux 架构的优点:

  1. 单一数据源,这样避免了子组件、父组件状态同步的问题
  2. 可以做到让组件无状态化
  3. 使用 Provider 注入,让 store actions 可以在子组件中,通过 props 访问使用

下面是一些不同点:

  1. mobx 使用的是 @inject 装饰器语法注入,redux 使用的是 connect 语法注入
  2. mobx 使用 @observer 语法,让一个 component 能响应 store 字段更新
  3. mobx 会动态精确绑定数据字段和对应 component 关系, redux 使用 connect 参数手动控制传递哪些字段
  4. mobx 直接修改 store 的状态,但是必须在 @action 修饰的函数中完成,@action 的语义,表示这是一个修改状态的操作
  5. redux Provider 传递 store 是强约定,mobx Provider 灵活传递 store actions,也可以是其它名字,比如 db
  6. redux 使用了比较难以理解的高阶函数和参数 connect combineReducers bindActionCreators mapStateToProps mapDispatchToProps ,mobx 方案,除了使用 decorator 语法,没有其它让人感觉理解困难的函数。
  7. redux 引入了数据流,mobx 没有数据流的概念,通过 actions 直接改变数据

编码工作量对比

代码功能少,感觉不到差别,好像就是 redux 方案有点难理解;而 mobx 比较直接,也比较 magic,就像当年刚开始使用 jQuery 的感觉。

现在给计数器增加乘以 2 倍的功能。

看下 两个方案的代码修改量差异

redux

mobx

两者都要在界面上做调整。

  • redux 方案需要要改 3 个地方: action_types、action_creator 、reducer
  • mobx 方案需要改 1 个地方: 添加一个 action

实现同样功能,redux 需要关注的地方多了 2/3。功能比较少的时候,感觉不到工作量差异多大。但是如果有个 500 个 action 要处理,这时候工作量的差距就是按时完成和加班也做不完的差别了。

这里是增加功能,同样,删除功能,也要删除更多的地方,改动更多的文件。

在实际项目中,action_types、action_creator 、reducer 分布于不同的文件夹,需要来回切换文件修改。

随着功能逐渐增加,redxu 方案,用一个 reducer 来处理,可能就不合适了,需要对 reducers 进行了拆分;mobx 方案也面临类似的问题,Actions、Store 类会越来越大。

如何扩展呢?

mobx 在大项目中的扩展能力

redux 方案,本质上还是通过添加更多的 switch 语句来实现扩展,将 store 分支节点的 reducer 分散到不同的文件,再通过工具函数combineReducers 合并成一个 rootReducer。

mobx 方案的扩展非常简单,需要扩展 store 和 actions。并且,actions 和 store 的扩展方式完全一致,通过给父类添加成员:

结论

为了不加班,我站 mobx 这边。

参考

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Felix的技术分享

xlog接入方案

1.1K30
来自专栏北京马哥教育

HTTP/2 十分钟速知

升级到 HTTP/2 后,那些针对HTTP/1.x 的优化手段需要如何变化? 答:总结来说,除了多域名增加并行 TCP 连接数不再适用以外,启用 HTTP/2...

42080
来自专栏北京马哥教育

逼格高又实用的 Linux 高级命令,开发运维都要懂

29450
来自专栏JAVA技术zhai

分享30道Redis面试题,面试官能问到的我都找到了

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到...

29020
来自专栏熊二哥

快速入门系列--WCF--06并发限流、可靠会话和队列服务

这部分将介绍一些相对深入的知识点,包括通过并发限流来保证服务的可用性,通过可靠会话机制保证会话信息的可靠性,通过队列服务来解耦客户端和服务端,提高系统的可服务数...

23270
来自专栏纯洁的微笑

一次线上问题排查所引发的思考

之前或多或少分享过一些内存模型、对象创建之类的内容,其实大部分人看完都是懵懵懂懂,也不知道这些的实际意义。

12710
来自专栏Golang语言社区

PHP调用Go服务的正确方式 - Unix Domain Sockets

作者:枕边书 链接:http://www.cnblogs.com/zhenbianshu/p/7265415.html 來源:博客园 问题 可能是由于经验太少,...

47090
来自专栏blackpiglet

使用 Docker 部署 MediaWiki

MediaWiki 是 Wikipedia 使用的网站解决方案的开源版,以个人观点来看,Wiki 在这个时代显得不够时尚,且不支持 MarkDown 等新兴的标...

33140
来自专栏Janti

记一次内存溢出的分析经历——thrift带给我的痛orz

说在前面的话 朋友,你经历过部署好的服务突然内存溢出吗? 你经历过没有看过Java虚拟机,来解决内存溢出的痛苦吗? 你经历过一个BUG,百思不得其解,头发一根一...

53280
来自专栏数据和云

快讯:Oracle 发布了传闻已久的 18.3 RPM 安装版本

关于 Oracle 发布数据库 RPM 安装版本的传闻已经有好几年了,今天 Oracle 终于发布了这个传说中、被期待的安装包,在 OTN 上已经可以下载 Li...

12330

扫码关注云+社区

领取腾讯云代金券