【五渣】那你来说说MobX和Redux吧

2,562 阅读7分钟

好久没有更新博客了,最近路飞已经五档了,竟然是什么人人果实·幻兽种·尼卡形态,路飞自己称之为五档,说是可以带来欢乐的果实🤷🏻‍♀️

因为最近在面试,项目中用到了Mobx,所以面试官经常会问到那MobX和Redux你觉得有什么区别呢,所以完事就看了看

现在在大型前端开发中,经常会用到两个自称为库的框架,一个React一个Vue(当然也可能是三大框架算上Angular)。在使用这个两个库的时候,状态在相邻组件中传递勉强还算方便,但是涉及到爷孙组件或者叔侄组件再或者表兄弟组件中的状态传递,那就不是说你props就能完美解决的了,虽然React有什么context,Vue有什么自定义事件或者EventBus,但是在使用上还有多多少少有点那么别别扭扭,所以会采用专门的状态管理来统一这些状态保存和操作,而Redux和MobX正是这样的管理“平台”

今天只说React,但是Redux和MobX并不局限于在React中使用

重点 重点 重点

Redux和MobX并不局限于在React中使用

先了解一下Redux和MobX

Redux是JavaScript应用的状态容器,提供可预测的状态管理

MobX是简单、可扩展的状态管理

MobX和Redux的github信息对比

这个是MobX和Redux的github信息对比,左边是MboX,右边是Redux。可以很明显的看出,不管是星星数还是关注数,都是Redux呈碾压性的获胜。但这并不能代表MobX是一个不好的状态管理库,只能说关注的人不多,宣传不到位😓

我觉得这两个状态库的关键词,一个是Redux的不可变值,一个是MobX的可观察的

Redux和MobX的相同点

  1. 都解决了状态管理中状态混乱,传递不便捷,无法有效同步状态的问题
  2. 通常都是与React之类的库一起使用。通常,之类,不是仅仅是React

Redux和MobX的不同点

数据流

Redux的数据流

Redux的数据流

初始阶段:调用一次reducer,传入的state作为初始state,并创建好store

更新阶段:

  • 触发页面事件,调用dispatch把一个action发送到store中。
  • store用之前的stateaction中的数据再一次调用reducer,并返回新的state作为新的state
  • store再去通知所有订阅(就是使用这个store中的数据)过的UI,通知他们store发生了变化。
  • 每个订阅过store数据的UI组件都会检查它们需要的state部分是否被更新
  • 发现数据被更新的每个UI组件强制使用新数据重新渲染,紧接着更新网页

MobX的数据流

MobX的数据流

MobX的数据就简单多了,就是触发actions,更改state的值,然后Mobx更改state的副作用就是更新UI,看似比Redux的要简单很多,其实是MobX在背后默默的帮我们实现了。

存储的数据结构

  1. Redux默认是存储的一个原生的JavaScript对象,而MobX则是存贮了一个可观察的对象
  2. Redux需要手动追踪所有状态对象的变更
  3. MobX中可以监听可观察对象,当其变更时讲自动触发监听(感觉炸一看跟Vue的双向绑定挺像,但是细看其实MobX还是需要组件触发事件,随后再去更改数据)

不可变(Immutable)和可变(Mutable)

Redux对状态的处理使用不可变值,通常是不可变的,我们来看Redux更新数据reducer中的一段代码

const store = {
    a: 1,
    b: 2
}

function Reducer(state = store, action) {
    const {type, payload} = action
    switch(type) {
        case 'XXX':
            return {
                ...state,
                a: payload.a
            };
        case 'YYY':
            return {
                ...state,
                b: payload.b
            };
        default: 
            return {
                ...state
            }
    }
}

Redux要求我们不能更改原操作对象,而是需要再原来状态的基础上返回一个新的状态对象(虽然我们现在这样只是浅拷贝,我们可以引入一个新的库immutable.js来完全拥抱不可变值

而MobX这边可以直接更改状态,继而更改视图数据

class Store {
    @observable a = 1;
    @observable b = 2;
    
    @action.bound
    changeA(num) {
        this.a = num
    }
    
    @action.bound
    changeB(num) {
        this.b = num
    }
}

export new Store()

其实我们在业务代码中直接写this.store.a = 123,但是这样的话,我们每更改一次,MobX就会更新很多次,而写进@aciton话我们可以得到一次最终值只更新一次(感觉有点类似React的setState);

函数式编程和面向对象编程

其实我们在看了上面的实例代码以后,我们很明显的就能看出来:

  1. Redux更拥抱函数式编程,这也更贴合React的思想(毕竟现在React的Hooks,你们懂的),因为Redux拥抱函数式编程,因此使用纯函数,函数获取输入,并输出,没有其他副作用
(state, action) => newState
  1. 而MobX拥抱的面向对象编程,一个store就是一个对象。因为MobX的值是可变的,所以我们可以这么写
function ChangeAny() {
    this.store.xxx = xxx
}

一个Store和多个Store

看到标题我们来看看谁是一个Store呢?在使用的时候我们觉得好像都是多个Store啊

  1. 在Redux中,我们其实是把状态保存在一个全局的store中或者全局的state中,一个数据来源保证了了数据的稳定,并支持多个reducer可以去更改他,可能有小伙伴觉得我们不是明明是多个store,然后最后用combineReducers合成一个的,对,就是这合成一个,当在组件中使用的使用的时候,我们只不过是拿到了单一数据源中的下面一层的数据,而不是直接拿到某个store的中的所有值

  2. 在MobX中,我们可以存在多个Store,每个对象就是一个Store,多个Store互相不受影响,需要更改某个Store中的对象,必须使用某个Store中的@action

总结: 其实在Redux中不是严格的单个Store,我们也可以创建多个Store,但是这样有违Redux的设计初衷,而且会使代码状态又混乱起来

可维护性

在打算总结这两个库的时候,我查了一些资料,很多的观点说什么MobX适合中小型项目,Redux有着严格的使用规范,所以更适合大型项目。

但是在我看来,其实这两个都适合大型项目,只是MobX可能需要更多的规范去制约多名开发者自己的开发习惯。

更不用说MobX可以更好的更新局部组件,类似有一个高度优化的shouldComponentUpdate

个人看法

更多的样板代码

可能有人会觉得Redux的样板代码很多,就比如你的action应该写,应该怎么写,你的reducer应该要写,应该怎么写,是用switch还是写if...else这一类的约束,而MobX则更加自由,想怎么改怎么改

但是我们要想MobX是怎么使一个变量可以被观察到,@observable里面的实现添加了各种监听代码


Redux看似更被大众接受,MobX可能现在依然小众吧(MobX用户不要喷我,数据确实这样)。Redux更偏向原生js的写法,MobX则有更多的装饰器。但是这两个都可以算是很成熟的库了,使用的时候可以根据自己的开发习惯,项目的要求,团队的接受程度来定使用哪一个,其实使用哪一个我都感觉不会错的~😘


我是五渣,想拿五杀