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 ...
随机推荐
- 【TouchGFX】代码结构
生成代码与用户代码 代码结构图示如下 据上图显示代码结构分为三层 引擎 这是TouchGFX提供的标准类,作为生成类的基类 生成 这是touchgfx designer生成的类,作为用户类的基类,这部 ...
- 【css】 text-align 居中导航
原理 :利用 inline-block 将 导航 作为 文本 , 被外层具有 text-align 属性的导航盒子包含 .从而实现居中效果 1. html 结构 <header> < ...
- Docker下的资源限制问题
Docker下的资源限制问题 问题背景 公司某产品出现了一个奇怪的OOM 错误提示. 问题现象是 前台产品 提示 OOM cannot create native thread 但是同时查看 机器的资 ...
- [转帖]iometer - 性能压力测试工具
<存储工具系列文章>主要介绍存储相关的测试和调试工具,包括不限于dd.fio.vdbench.iozone.iometer.cosbench等性能负载工具,及strace等调试工具. 1 ...
- [转帖]Prometheus监控系统存储容量优化攻略,让你的数据安心保存!
云原生监控领域不可撼动,Prometheus 是不是就没缺点?显然不是. 一个软件如果什么问题都想解决,就会导致什么问题都解决不好.所以Prometheus 也存在不足,广受诟病的问题就是 单机存储不 ...
- [转帖]2022年 SRE、DevOps技能图谱
https://zhuanlan.zhihu.com/p/568752990 在过去一段时间,我面试过一些 DevOps 相关从业者,并且曾经收到过一些知乎小伙伴的提问,针对于 DevOps 以及相关 ...
- [转贴]一图弄懂ASCII、GB2312、GBK、GB18030编码
一图弄懂ASCII.GB2312.GBK.GB18030编码 https://blog.csdn.net/LightUpHeaven/article/details/92008630 转载君子不器. ...
- Mysql到TiDB迁移,双写数据库兜底方案
作者:京东零售 石磊 TiDB 作为开源 NewSQL 数据库的典型代表之一,同样支持 SQL,支持事务 ACID 特性.在通讯协议上,TiDB 选择与 MySQL 完全兼容,并尽可能兼容 MySQL ...
- 希尔伯特变换用于解调系统——以解调调频信号为例,FM Demodulation
What's The Hilbert Transform 简单地说,希尔伯特变换的物理意义为:把信号的所有频率分量的相位推迟90度,这样原信号和变换后信号可以视为一组IQ正交信号,在数字域正交化,可以 ...
- 从零开始配置vim(21)——lsp简介与treesitter 配置
截止到上一篇文章,我们配置了neovim的很多内容了.具备了一些编辑器的常用功能了,而且可以胜任日常的文档编辑工作了.但是想作为一个可靠的代码编辑器还缺少重要的一环,即代码语法部分的支持. 在过去的v ...