Mobx与Redux的异同
Mobx与Redux的异同
Mobx与Redux都是用来管理JavaScript应用的状态的解决方案,用以提供在某个地方保存状态、修改状态和更新状态,使我们的应用在状态与组件上解耦,我们可以从一个地方获得状态,在另一个地方修改,在其他地方得到他们更新后的状态。他们都遵循单一数据源的原则,这让我们更容易推断状态的值和状态的修改。当然他们并不一定要跟React绑定在一起,它们也可以在AngularJs和VueJs这些框架库里使用。
描述
Redux作者说过,如果你不知道是否需要Redux,那就是不需要。在判断是否需要使用Mobx与Redux之前,我们首先需要知道他们究竟是要解决什么问题,以及当前是否遇到了这个问题。如今前端通常是要用组件components来构建一个应用,而组件中通常有自己的内部状态即state,但是随着应用越来越膨胀,组件自己内部维护的状态在膨胀的应用中很快会变得混乱。随着应用功能的不断拓展,通常会出现一些问题:
- 一个组件通常需要和另一个组件共享状态。
- 一个组件需要改变另一个组件的状态。
- 组件层级太深,需要共享状态时状态要层层传递。
- 子组件更新一个状态,可能有多个父组件,兄弟组件共用,实现困难。
这种情况下继续使用提取状态到父组件的方法你会发现很复杂,而且随着组件增多,嵌套层级加深,这个复杂度也越来越高。因为关联的状态多,传递复杂,很容易出现像某个组件莫名其妙的更新或者不更新的情况,异常排查也会困难重重。也就是说当应用膨胀到一定程度时,推算应用的状态将会变得越来越困难,此时整个应用就会变成一个有很多状态对象并且在组件层级上互相修改状态的混乱应用。在很多情况下,状态对象和状态的修改并没有必要绑定在一些组件上,我们可以尝试将其提升,通过组件树来得到与修改状态。
目前通常的解决方案是引入状态管理库,比如Mobx或Redux,Mobx与Redux都是用来管理JavaScript应用的状态的解决方案,用以提供在某个地方保存状态、修改状态和更新状态,使我们的应用在状态与组件上解耦,我们可以从一个地方获得状态,在另一个地方修改,在其他地方得到他们更新后的状态。他们都遵循单一数据源的原则,这让我们更容易推断状态的值和状态的修改。当然他们并不一定要跟React绑定在一起,它们也可以在AngularJs和VueJs这些框架库里使用。
像Redux和Mobx这类状态管理库一般都有附带的工具,例如在React中使用的有react-redux和mobx-react,他们使你的组件能够获得状态,一般情况下,这些组件被叫做容器组件container components,或者说的更加确切的话,就是连接组件connected components。通常只要将组件作为连接组件,就可以在组件层级的任何地方得到和更改状态。
对于Mobx与Redux的异同这个问题,是我最近在找实习的时候遇到的,分别为react mobx与react redux作简单的示例,文中的示例代码都在https://codesandbox.io/s/react-ts-template-forked-88t6in中。
Mobx
MobX是一个经过战火洗礼的库,他通过透明的函数响应式编程transparently applying functional reactive programming - TFRP使得状态管理变得简单和可扩展。MobX背后的哲学很简单: 任何源自应用状态的东西都应该自动地获得,其中包括UI、数据序列化等等,核心重点就是: MobX通过响应式编程实现简单高效,可扩展的状态管理。
// src/mobx-store/store.ts
import { observable, action, makeAutoObservable } from "mobx";
class Store {
constructor() {
makeAutoObservable(this);
}
@observable
state = {
count: 1
};
@action
setCount = (value: number) => {
this.state.count = value;
};
@action
setCountIncrement = () => {
this.state.count++;
};
}
export default new Store();
// src/counter-mobx.tsx
import React from "react";
import { observer } from "mobx-react";
import store from "./mobx-store/store";
const CountMobx: React.FC = () => {
return (
<div>
<div>{store.state.count}</div>
<button onClick={() => store.setCount(1)}>Set Count value 1</button>
<button onClick={store.setCountIncrement}>Set Count Increment</button>
</div>
);
};
export default observer(CountMobx);
Redux
Redux用一个单独的常量状态树或者叫作对象保存这一整个应用的状态,这个对象不能直接被改变,当一些数据变化了,一个新的对象就会被创建,严格的单向数据流是Redux架构的设计核心。
// src/redux-store/store.ts
import { createStore } from "redux";
const defaultState: State = {
count: 1
};
export const actions = {
SET_COUNT: "SET_COUNT" as const,
SET_COUNT_INCREMENT: "SET_COUNT_INCREMENT" as const
};
const reducer = (state: State = defaultState, action: Actions): State => {
const { type } = action;
switch (type) {
case actions.SET_COUNT: {
return { ...state, count: action.payload };
}
case actions.SET_COUNT_INCREMENT: {
return { ...state, count: state.count + 1 };
}
default:
return state;
}
};
export const store = createStore(reducer, defaultState);
export interface State {
count: number;
}
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
type SET_COUNT_INCREMENT = {
type: typeof actions.SET_COUNT_INCREMENT;
payload: void;
};
type SET_COUNT = {
type: typeof actions.SET_COUNT;
payload: number;
};
export type Actions = SET_COUNT_INCREMENT | SET_COUNT;
// src/counter-redux.tsx
import React from "react";
import { AppDispatch, actions, State } from "./redux-store/store";
import { useSelector, useDispatch } from "react-redux";
const CountRedux: React.FC = () => {
const count = useSelector((state: State) => state.count);
const dispatch = useDispatch() as AppDispatch;
return (
<div>
<div>{count}</div>
<button onClick={() => dispatch({ type: actions.SET_COUNT, payload: 1 })}>
Set Count value 1
</button>
<button
onClick={() =>
dispatch({ type: actions.SET_COUNT_INCREMENT, payload: void 0 })
}
>
Set Count Increment
</button>
</div>
);
};
export default CountRedux;
// src/App.tsx
import React from "react";
import "./styles.css";
import CountMobx from "./counter-mobx";
import CountRedux from "./counter-redux";
import { Provider as ReduxProvider } from "react-redux";
import { store } from "./redux-store/store";
const App: React.FC = () => {
return (
<div>
<div>======Mobx======</div>
<CountMobx />
<br />
<div>======Redux======</div>
<ReduxProvider store={store}>
<CountRedux />
</ReduxProvider>
</div>
);
};
export default App;
相同点
- 为了解决状态管理混乱,无法有效的同步的问题,统一管理应用状态。
- 一个状态只有一个可信的数据源,通常是以
action的方式提供更新状态的途径。 - 都带有状态与组件的链接管理库,例如
react-redux、mobx-react。
不同点
函数式和面向对象
Redux更多的是遵循函数式编程Functional Programming, FP思想,从数据上来说Redux理想的是immutable,immutable对象是不可直接赋值的对象,它可以有效的避免错误赋值的问题,例如reducer就是一个纯函数,对于相同的输入总是输出相同的结果。Mobx则更多从面相对象Object Oriented Programming, OOP与响应式编程Reactive Programming角度考虑问题,从数据上说Mobx从始至终都是一份引用,这样可以使的Mobx的组件可以做到精准更新,将状态包装成可观察对象,一旦状态对象变更,就能自动获得更新。
store管理方式
- 在
Redux应用中通常将整个应用的state被储存在一棵object tree中,并且这个object tree只存在于唯一一个store中。 - 在
Mobx则通常按模块将应用状态划分,在多个独立的store中管理。
储存数据形式
Redux默认以JavaScript原生对象形式存储数据,这也就使得Redux需要手动追踪所有状态对象的变更。- 在
Mobx使用可观察对象,通常是使用observable让数据的变化可以被观察,通过把属性转化成getter/setter来实现,当数据变更时将自动触发监听响应。
不可变和可变
Redux状态对象通常是不可变的Immutable,复制代码我们不能直接操作状态对象,而总是在原来状态对象基础上返回一个新的状态对象。Mobx状态对象通常是可变的Mutable,可以直接使用新值更新状态对象。
状态调试
Redux提供进行时间回溯的开发工具,同时纯函数以及更少的抽象,让调试变得更加容易。Mobx中有更多的抽象和封装,调试会相对比较困难,同时结果也相对难以预测。
最后
Mobx与Redux都是非常棒的两个库,使用上没有对错,只有合适不合适,只是可能需要在使用之前做好调研工作。或许有人需要减少编写的代码行数,那么就可能会提到Redux有太多的样板代码,而应该使用Mobx,可以减少xxx行代码。又或许有人需要更加明确的处理对象的变更,那么就可能感觉放弃Mobx的响应式魔法,而使用Redux去通过纯 JavaScript来推断与调试。又或许两个状态管理库并不冲突,可以同时存在,分别管理不同的模块的状态。
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://cn.mobx.js.org/
https://www.redux.org.cn/docs/react-redux/
https://juejin.cn/post/6844903977553756168
https://juejin.cn/post/6924572729886638088
https://segmentfault.com/a/1190000011148981
https://www.cnblogs.com/tommymarc/p/15768138.html
https://blog.csdn.net/leelxp/article/details/108450518
https://blog.csdn.net/Ed7zgeE9X/article/details/121896197
https://yangleiup.github.io/accumulate/redux%E4%B8%8Emobx%E5%8C%BA%E5%88%AB.html
https://medium.com/@pie6k/better-way-to-create-type-safe-redux-actions-and-reducers-with-typescript-45386808c103
Mobx与Redux的异同的更多相关文章
- 你需要Mobx还是Redux?
在过去一年,越来越多的项目继续或者开始使用React和Redux开发,这是目前前端业内很普遍的一种前端项目解决方案,但是随着开发项目越来越多,越来越多样化时,个人又有了不同的感受和想法.是不是因为已经 ...
- Mobx与Redux区别
Mobx的实现思想和Vue几乎一样,所以其优点跟Vue也差不多:通过监听数据(对象.数组)的属性变化,可以通过直接在数据上更改就能触发UI的渲染,从而做到MVVM.响应式.上手成本低.开发效率高,在数 ...
- Mobx总结以及mobx和redux区别
Mobx解决的问题 传统react使用的数据管理库为Redux.Redux要解决的问题是统一数据流,数据流完全可控并可追踪.要实现该目标,便需要进行相关的约束 Redux由此引出dispatch ac ...
- 几个月来使用mobx代替redux的一些总结
遇到的一些小坑 React组件内部想要调用store里的action方法,得如下图,否则不会调用(这个现在看来好像不对,待重新检验) 而不能如下图 组件中调用改变store的action后,状态变化并 ...
- redux、immutablejs和mobx性能对比(三)
四.我的结论 通过第三部分的数据数据分析,我觉得我们可以得到以下结论: 无论是在开发环境还是测试环下页面的首次加载速度结果都是:redux>immutablejs>mobx,但是他们之间的 ...
- 在react项目中使用redux or mobx?
主要比较参数: 库体积,打包项目体积 开发体验 性能对比 在对比参数前首先分析一下redux和mobx的设计模式,redux和mobx都没有使用传统的mvc/mvvm形式,而且他们使用flux结构也略 ...
- 【译】Redux 还是 Mobx,让我来解决你的困惑!
原文地址:Redux or MobX: An attempt to dissolve the Confusion 原文作者:rwieruch 我在去年大量的使用了 Redux,但我最近都在使用 Mob ...
- Redux/Mobx/Akita/Vuex对比 - 选择更适合低代码场景的状态管理方案
近期准备开发一个数据分析 SDK,定位是作为数据中台向外输出数据分析能力的载体,前端的功能表现类似低代码平台的各种拖拉拽.作为中台能力的载体,SDK 未来很大概率会需要支持多种视图层框架,比如Vue2 ...
- 十分钟介绍mobx与react
原文地址:https://mobxjs.github.io/mobx/getting-started.html 写在前面:本人英语水平有限,主要是写给自己看的,若有哪位同学看到了有问题的地方,请为我指 ...
- mobx源码解读1
mobx是redux的代替品,其本身就是一个很好的MVVM框架.因此花点力气研究一下它. 网上下最新的2.75 function Todo() { this.id = Math.random() mo ...
随机推荐
- B2033 A*B 问题
A*B 问题 题目描述 输入两个正整数 \(A\) 和 \(B\),求 \(A \times B\) 的值.注意乘积的范围和数据类型的选择. 输入格式 一行,包含两个正整数 \(A\) 和 \(B\) ...
- 【水一篇】骚操作之net 6的winform启动的同时启动Net 6 WebApi【同一套代码】
引言 有段时间没有写博客了,不知道写什么,加上最近一直在玩单片机方面的东西,所以有一些懈怠.首先呢,为什么会有这么一个问题,是在一个QQ群里,有看到有人提问,能不能在启动Winform的同时去启动一个 ...
- [转帖]Java和Scala的前世今生
第一部分:Java 计算机语言介绍 第一代语言:机器语言.指令以二进制代码形式存在 第二代语言:汇编语言.使用助记符表示一条机器指令 第三代语言:高级语言 C.Pascal.Fortran面向过程的语 ...
- Mysql8.0.32 union all创建视图无法使用中文模糊查询的坑
Mysql8.0.32 union all创建视图无法使用中文模糊查询的坑 摘要 本周研发同事反馈现场有一个问题. 客户使用mysql的数据库(Windows平台) 然后在多表union all 创建 ...
- [转帖]Full GC (Ergonomics) 产生的原因
发生Full GC,有很多种原因,不仅仅是只有Allocation Failure. 还有以下这么多: #include "precompiled.hpp" #include &q ...
- [转帖]Elasticsearch-索引性能调优
1:设置合理的索引分片数和副本数 索引分片数建议设置为集群节点的整数倍,初始数据导入时副本数设置为 0,生产环境副本数建议设置为 1(设置 1 个副本,集群任意 1 个节点宕机数据不会丢失:设置更多副 ...
- [转帖]Redis各版本特性汇总
redis4 redis5 redis6 redis6.2 重大特性 1.模块系统 2.PSYNC2 3.LFU淘汰策略 4.混合RDB-AOF持久化 5.LAZY FREE延迟释放 6.MEMORY ...
- [转帖]基本系统调用性能lmbench测试方法和下载
简介 Lmbench是一套简易,可移植的,符合ANSI/C标准为UNIX/POSIX而制定的微型测评工具.一般来说,它衡量两个关键特征:反应时间和带宽. Lmbench旨在使系统开发者深入了解关键操作 ...
- [转帖]一次fork引发的惨案!
https://www.cnblogs.com/xuanyuan/p/15502289.html "你还有什么要说的吗?没有的话我就要动手了",kill程序最后问道. 这一次,我没 ...
- 学习MySQL中DDL语句的修改字段与删除字段,删除表
连接本地mysql语句 mysql -hlocalhost -uroot -proot 显示表结构 语法:desc 表名 查看某一个表结构以及注释 语法:show create table 表名 sh ...