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 ...
随机推荐
- java - 正确关闭流
package stream; import java.io.*; public class FileReaderTest { public static void main(String[] arg ...
- [转帖]字符集 AL32UTF8 和 UTF8
https://blog.51cto.com/comtv/383254# 文章标签职场休闲字符集 AL32UTF8 和 UTF8文章分类数据库阅读数1992 The difference betwee ...
- Nginx日志规则以及根据日志进行性能问题判断的思路
Nginx日志规则以及根据日志进行性能问题判断的思路 背景 Nginx是开源方案里面能实现反向代理 负载均衡的首选. 但是有时候性能出问题比较难以分析和定位, 不知道是不是nginx的瓶颈 性能问题的 ...
- [转帖]Django10——从db.sqlite3迁移到MySQL
https://blog.csdn.net/weixin_47197906/article/details/124889477 文章目录 1.查看Django支持的数据库 2.修改数据库配置 1.查看 ...
- [转帖]一口气看完45个寄存器,CPU核心技术大揭秘
https://www.cnblogs.com/xuanyuan/p/13850548.html 序言 前段时间,我连续写了十来篇CPU底层系列技术故事文章,有不少读者私信我让我写一下CPU的寄存器. ...
- [转帖]Native Memory Tracking 详解(2):追踪区域分析(一)
https://www.modb.pro/db/529363 上篇文章 Native Memory Tracking 详解(1):基础介绍 中,分享了如何使用NMT,以及NMT内存 & OS内 ...
- Nginx编译安装与常用配置模板
Nginx编译安装与常用配置模板 背景 是在受不了每次都是先去百度,找模板了. 这次将几个常用模板整理一下, 以后不管在哪里可以直接使用. 注意: 不能直接用于生产, 可用于测试与POC 第一部分编译 ...
- vue如何在render函数中循环(3)
h函数的三个参数 第一个参数是必须的. 类型:{String | Object | Function} 一个 HTML 标签名.一个组件.一个异步组件.或一个函数式组件. 是要渲染的html标签. 第 ...
- Mygin实现中间件Middleware
本篇是mygin的第六篇,参照gin框架,感兴趣的可以从 Mygin第一篇 开始看,Mygin从零开始完全手写,在实现的同时,带你一窥gin框架的核心原理实现. 目的 实现中间件Middleware ...
- Jupyter Notebook支持Go
在执行下列命令之前,请确保你已经安装了Go和Jupyter. gophernotes是针对Jupyter和nteract的Go内核,它可以让你在基于浏览器的笔记本或桌面app上交互式地使用Go.下面介 ...