前言
- vue: vuex
- react:redux、mobx(v4/5、v6)、recoil
在这里,暂不细致比较 redux,就个人而言,不选择 redux 有以下几点
- 首先 Redux 这一套的机制,React Hooks 本身就已经实现,useReducer、useContext,没有必要
- 重要的一点,redux 数据流机制是从上至下传递,与当前流行的 “即插即用”的设计原则不符,并且开发成本较 mobx 与 recoil 要高(umi、dva除外,umi学习和维护成本较高、dva不太灵活,它们有些限制)
整体对比
- mobxjs/mobx (v6):https://github.com/mobxjs/mobx
- facebook/Recoil :https://github.com/facebookexperimental/Recoil
对比项 | mobx | recoil | Github Star 数 | 23.1k | 11.4k | React hooks 支持 | mobx v6 + mobx-react - mobx 是可观察数据对象工具,可以在react、vue、js项目中使用 - mobx-react 是将可观察对象与react关联起来的工具 | 无需额外辅助工具,天然支持 | UI与逻辑 解耦 | 支持 - react 调用 store的action,逻辑在store中处理 | 不支持 - react调用 recoil的 useRecoilState API,在组件中实现业务逻辑,比如: const [amount, setAmount] = useRecoilState(amountState) | 单例与多例 | - export default new Store() 内部实例化,为单例 - export default Store,引用处实例化,为多例 通过程序控制,较为灵活,便于定制化 | 每一个atom 和 selector 都是单例 | 数据流向(单项目) | - globalStore => Root => React.FC - pageStore => React.FC | atom[ => selector] => React.FC | 状态感应 | when,reaction | 不支持 | store间交互 | 支持 | 不支持 | 常用 API 数(个) | 5+ | 6+ | 学习成本 | 较低 | 较低 | 理解成本 | 低 | 中 | 开发体验 | 友好 | 一般,甚至有点麻烦,不适合大型项目 |
---|
基本使用对比
mobx
- 以 testStore 为例
import { makeAutoObservable, runInAction } from 'mobx';
class TestStore {
amount = 1; // observable state
data; // observable state
constructor() {
// 自动监听所有属性
makeAutoObservable(this);
}
// computed
get price(): string {
return `$${this.amount * 100}`;
}
// action
increment(): void {
this.amount++;
}
// async action,
async asyncAction(id: string): Promise<void> {
try {
const data = await geAsyncData(id);
// 异步action中,改变状态时,外层要包裹 runInAction(() => {/** ...*/})
runInAction(() => {
this.data = data;
});
} catch (e) {
throw new Error(e);
}
}
}
export default new TestStore();
- Use In React:需结合 mobx-react
import { FC } from 'react';
import { observer } from 'mobx-react';
import store from './testStore';
const Test: FC = () => {
return (
<div>
<div>count: {store.amount}</div>
<div>price: {store.price}</div>
<button type="button" onClick={() => store.increment()}>add +1</button>
<button type="button" onClick={() => store.asyncAction(1)}>异步请求</button>
</div>
);
};
// 监听 Component
export default observer(Test);
recoil
- recoil 的数据都是粒子,铺平的,
import { atom, selector } from 'recoil';
// state
export const amountState = atom({
key: 'amountState',
default: 0,
});
// computed
export const priceState = selector({
key: 'priceState',
get: ({ get }) => {
return `$${get(amountState) * 100}`; ;
}
});
// async state request
export const asyncTestData = selector({
key: 'asyncTestData',
get: async ({ get }) => {
return await geAsyncData();
}
});
// what's the fuck,if you want request async data with params in recoil-store, you must use another API "selectorFamily"
// async state request with params
export const asyncTestDataWithParams = selectorFamily({
key: 'asyncTestDataWithParams',
get: id => async ({ get }) => {
return await geAsyncData(id);
}
});
- Use In React
import { FC } from 'react';
import { useRecoilState, useRecoilValue } from 'mobx-react';
import { amountState, priceState, asyncTestDataWithParams } from './testStore';
const Test: FC = () => {
const [amount, setAmount] = useRecoilState(amountState);
const price = useRecoilValue(priceState);
const getData = () => {
return userRecoilValue(asyncTestDataWithParams(1));
}
return (
<div>
<div>count: {amount}</div>
<div>price: {price}</div>
<button type="button" onClick={() => setAmount(amount + 1)}>add +1</button>
<button type="button" onClick={() => getData()}>异步请求</button>
</div>
);
};
// 监听 Component
export default observer(Test);
状态感应
- 状态感应:当AStore的某个可观察数据达到条件时,会自动触发本store的其他动作 或 触发其他store的动作,程序描述就是 when(A.isReady === true) => B.action()
- recoil 粒子说,不存在此场景
- mobx 支持状态感应场景
class TestStore {
isReady = false;
count = 0;
constructor() {
makeAutoObservable(this);
// 监听isReady,当 isReady 变为 true 时,执行 doSomething(一次性行为)
when(() = this.isReady, () => this.doSomething());
// 监听amount,当 amount 每次变化后,都会输出 value, previousValue
reaction(
() => this.amount,
(value, previousValue) => {
console.log(value, previousValue);
}
);
}
doReady(): void {
this.isReady = true;
}
doSomething(): void {
...
}
increment(): void {
this.amount++;
}
}
Store间交互
- recoil:不支持
- mobx:基于 store实例的单例模式,且 store之间可以互相引用和调用,可以实现通过store来控制数据流的初始化控制
import stores from './installStores';
class ScheduleStore {
isRunning = false;
constructor() {
makeAutoObservable(this);
}
async run(): Promise<void> {
try {
// 用户信息初始化
await stores.userStore.init();
await stores.testStore.init();
runInAction(() => {
this.isRunning = true;
});
} catch (e) {
console.log(e);
}
}
}
Store形式
- mobx: 一个 store 为一个class,便于功能扩展:继承 class、实现接口
- Recoli:一个个粒子store,无法扩展,承接高级用法
尾声
mobx 与 recoil 基本对比分析已经OK、总之,各有各的特点,都是非常优秀数据管理工具,在技术选型时,还需参考项目实际应用场景和开发成本,希望本文能对你有所有帮助。
如果想继续了解 mobx ,可以阅读 react hooks + mobx usage of summary
参考文献
❤️ 加入我们
字节跳动 · 幸福里团队
Nice Leader:高级技术专家、掘金知名专栏作者、Flutter中文网社区创办者、Flutter中文社区开源项目发起人、Github社区知名开发者,是dio、fly、dsBridge等多个知名开源项目作者
期待您的加入,一起用技术改变生活!!!
招聘链接: job.toutiao.com/s/JHjRX8B
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!