Skip to main content

· 8 min read
jackshen

前言

当我们使用 React 开发 web 应用程序时,当项目越发复杂,我们发现仅仅使用 React 的 setState 方法已经无法适应如此复杂的状态管理了,程序状态变得比较难同步,操作,到处是回调,发布,订阅,这意味着我们需要更好的状态管理方式,于是就引入了状态管理库,如 Redux,Mobx,Dva,Rematch 等。

Mobx VS Redux

目前来看,Redux 已是 React 应用状态管理库中的霸主了,而 Mobx 则是一方诸侯,我们为什么要选择 Mobx,而不是使用 Redux 呢。要回答这个问题,我们先来看一下我们实际的业务场景,毕竟选择任何一个状态管理库都是为了解决实际问题。 我们的业务场景特点

  1. 单页 SPA 架构,页面切换通过 history 路由来实现
  2. 多标签页,类似于浏览器的标签页,一个标签页就是一个菜单
  3. 基于约定式路由,每一个页面都是一个组件,每一个组件都可以独立工作,并不依赖其它组件
  4. 系统复杂,页面很多,但页面与页面之间基本上没有关系,也不存在数据共享的问题
  5. 系统按照不同模块拆分,不同人各负责一个或多个模块,每个人的技术能力、业务能力都有差别
  6. 没有数据缓存的需求,也即不支持浏览器的回退功能

在选择 Mobx 之前,我们也调研过 Redux,Redux 的数据流管理还是相对复杂些,它有个特点就是集中式的状态管理,类似于后台 MVC 的分层思想,按照约定的目录编写业务逻辑,由于是集中式的数据流管理,数据都维护在同一个地方,所以要做回退的功能就比较容易,在某些场景下(例如移动端场景),这个特性非常好。那回过头来看我们的业务场景,发现 Redux 并不能很好解决问题,主要有几点:

  1. 每一个页面组件都是独立的,状态数据也是隔离的,而 Redux 是集中式的状态管理,不便于做数据隔离(虽然也是有办法的)
  2. 多标签页的场景下,在标签页之间切换时不能让页面组件重新渲染,Redux 是单一 store 模式,意味着每次切换都有重新加载页面数据,难度和风险比较大;
  3. 我们有些业务场景非常复杂,页面中的交互很多,每次改变数据如果都走 Redux 的数据流,会比较繁琐而且也不够简单。

而 Mobx 能相对很好的解决以上问题

  1. Mobx 是多 store 模式,意味着每一个组件都可以拥有自己的 store,管理自己的数据,而不会影响到其它的组件。
  2. 在多标签页的模式下,每一个页面都是独立的,利用 Mobx 可以很好地做到数据隔离
  3. Mobx 相对简单,特别是数据观察这一块,能够比较直观的反映数据的变化(有点像双向数据绑定),上手比较方便
  4. 组件的复用比较简单,当我们开发一个公共业务组件时,理想是一个无状态组件(SFC),但是现实是很难做到的,总会有一些副作用(例如接口调用);如果交互比较复杂,还需要引入状态管理,Mobx是多store模式的,意味着业务组件内部完全可以有自己的状态管理,当组件复用时,不用关心组件的内部实现,而Redux是统一store,要做到这一点比较难。

Mobx vs Hooks

React16.8 新增的 Hooks,让 React 的状态管理多了一种选择,特别是在函数式编程越来越流行的今天,Hooks 也受到更多人的青睐,在一些简单场景下,甚至不用引入 Redux/Mobx,单纯用 Hooks 就可以解决问题了,那么 Hooks 和 Mobx 是不是只能二选一呢,答案肯定不是的,我认为 Mobx 是 Hooks 的一种补充,如果交互比较简单,推荐 Hooks 就可以解决问题了,如果交互比较复杂,还是选择专业的状态管理库靠谱些(但并不代表 Hooks 不能用在复杂的场景中)。

下面我给出一个示例,一个简单的累计器,分别用 Hooks 和 Mobx 来实现

import React from 'react';
import { Button } from 'antd';
const styles = require('./index.less');

const Counter = () => {
const [count, setCount] = React.useState(0);

const incrementCount = React.useCallback(() => {
setCount(count + 1);
}, [count]);

const decrementCount = React.useCallback(() => {
setCount(count - 1);
}, [count]);

return (
<div className={styles.root}>
<Button type="primary" onClick={incrementCount}>
+
</Button>
<Button onClick={decrementCount}>-</Button>
<h1> Count: {count}</h1>
</div>
);
};

export default Counter;

效果如下,可以看到,如果是简单的数据管理,用hooks就可以了(甚至用setState都行),用Mobx有点大材小用

PNG