好久没有更新博客了,最近路飞已经五档了,竟然是什么人人果实·幻兽种·尼卡形态,路飞自己称之为五档,说是可以带来欢乐的果实🤷🏻♀️
因为最近在面试,项目中用到了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信息对比,左边是MboX,右边是Redux。可以很明显的看出,不管是星星数还是关注数,都是Redux呈碾压性的获胜。但这并不能代表MobX是一个不好的状态管理库,只能说关注的人不多,宣传不到位😓
我觉得这两个状态库的关键词,一个是Redux的不可变值,一个是MobX的可观察的
Redux和MobX的相同点
- 都解决了状态管理中状态混乱,传递不便捷,无法有效同步状态的问题
- 通常都是与React之类的库一起使用。通常,之类,不是仅仅是React
Redux和MobX的不同点
数据流
Redux的数据流
初始阶段:调用一次reducer
,传入的state
作为初始state
,并创建好store
;
更新阶段:
- 触发页面事件,调用
dispatch
把一个action
发送到store
中。 store
用之前的state
和action
中的数据再一次调用reducer
,并返回新的state
作为新的state
。store
再去通知所有订阅(就是使用这个store中的数据)过的UI,通知他们store
发生了变化。- 每个订阅过
store
数据的UI组件都会检查它们需要的state
部分是否被更新 - 发现数据被更新的每个UI组件强制使用新数据重新渲染,紧接着更新网页
MobX的数据流
MobX的数据就简单多了,就是触发actions
,更改state
的值,然后Mobx更改state
的副作用就是更新UI,看似比Redux的要简单很多,其实是MobX在背后默默的帮我们实现了。
存储的数据结构
- Redux默认是存储的一个原生的JavaScript对象,而MobX则是存贮了一个可观察的对象
- Redux需要手动追踪所有状态对象的变更
- 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
);
函数式编程和面向对象编程
其实我们在看了上面的实例代码以后,我们很明显的就能看出来:
- Redux更拥抱函数式编程,这也更贴合React的思想(毕竟现在React的Hooks,你们懂的),因为Redux拥抱函数式编程,因此使用纯函数,函数获取输入,并输出,没有其他副作用
(state, action) => newState
- 而MobX拥抱的面向对象编程,一个store就是一个对象。因为MobX的值是可变的,所以我们可以这么写
function ChangeAny() {
this.store.xxx = xxx
}
一个Store和多个Store
看到标题我们来看看谁是一个Store呢?在使用的时候我们觉得好像都是多个Store啊
-
在Redux中,我们其实是把状态保存在一个全局的store中或者全局的state中,一个数据来源保证了了数据的稳定,并支持多个
reducer
可以去更改他,可能有小伙伴觉得我们不是明明是多个store,然后最后用combineReducers
合成一个的,对,就是这合成一个,当在组件中使用的使用的时候,我们只不过是拿到了单一数据源中的下面一层的数据,而不是直接拿到某个store的中的所有值 -
在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则有更多的装饰器。但是这两个都可以算是很成熟的库了,使用的时候可以根据自己的开发习惯,项目的要求,团队的接受程度来定使用哪一个,其实使用哪一个我都感觉不会错的~😘
我是五渣,想拿五杀