官方文档 https://www.mobxjs.com/
moxb 和 redux 都能用于 react 的状态管理,但 moxb 更简单,适合规模不大的应用 (规模大的应用若合理组织代码结构,也能用 moxb)
安装 moxb
npm i mobx
npm i mobx-react-lite
- 此处安装 mobx-react-lite 仅可用于函数组件,不支持类组件
- 若想同时支持类组件和函数组件,则需安装 mobx-react
moxb 的工作流程
moxb 的目录结构
- 在 src 目录下创建文件夹 store
- 在文件夹 store 中根据需要创建 js/ts 文件,比如常用的全局状态–当前登录用户,则创建 User.js 文件
moxb 的基本使用
1. 定义响应式的属性和方法
以 User.js 为例,详见注释
import { makeAutoObservable } from "mobx";
// 定义类
class User {
// 构造函数
constructor() {
/** 【自动创建响应式】
* 第1个参数:要创建为响应式的对象,此处的this即指当前类
* 第2个参数:默认第1个参数的所有属性和方法都会添加响应式,可在此指定不添加响应式的属性和方法,如{if_Login:false},即属性if_Login无响应式
* 第3个参数:指定自动绑定this,方便在页面使用时,绑定事件无参数时可不使用箭头函数
*/
makeAutoObservable(this, {}, { autoBind: true });
}
// 属性 if_Login --- 用户是否登录
if_Login = false;
// 属性 info --- 用户的信息
info = {};
// 方法 -- 用户登录
login(newInfo) {
// 将属性 if_Login 的值设置为 true
this.if_Login = true;
// 将传入的参数赋值给属性 info
this.info = newInfo;
}
// 方法 -- 用户登出
logout() {
// 将属性 if_Login 重置为 false
this.if_Login = false;
// 将属性 info 重置为 {}
this.info = {};
}
}
// 导出类实例
export default new User();
2. 在页面中使用
- 需用 observer 函数包裹目标组件,这样页面才能随状态值的变化渲染更新
index.jsx
// 导入实例 User
import User from "./store/User.js";
// 导入 observer 函数
import { observer } from "mobx-react-lite";
// 用 observer 函数包裹目标组件
const Demo = observer(() => {
return (
<>
{/* 获取实例 User 的属性 if_Login 的值 */}
<div>登录状态:{User.if_Login ? "已登录" : "未登录"}</div>
{/* 获取实例 User 的属性 info 值的 name 属性的值 */}
<div>用户名称:{User.info.name}</div>
{/* 调用实例 User 的方法 login,因有自定义传参,需使用箭头函数 */}
<button onClick={() => User.login({ name: "朝阳" })}>登录</button>
{/* 调用实例 User 的方法 logout */}
<button onClick={User.logout}>登出</button>
</>
);
});
export default Demo;
最终效果
moxb 的自动计算 computed
与 vue 的 computed 概念相同,在响应式方法前加上 get
即可实现
src/store/Counter.js
import { makeAutoObservable } from "mobx";
class Counter {
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
value = 0;
increase() {
this.value++;
}
// 用 get 装饰的方法,即computed,会随方法内响应式属性的变化,自动计算
get double() {
return this.value * 2;
}
}
export default new Counter();
src/index.js
import Counter from "./store/Counter.js";
import { observer } from "mobx-react-lite";
const Demo = observer(() => {
return (
<>
<div>计数器的值为:{Counter.value}</div>
<div>双倍的计数器值为:{Counter.double}</div>
<button onClick={Counter.increase}>+1</button>
</>
);
});
export default Demo;
moxb 监听属性
autorun
与 vue3 的 watchEffect 的概念相同,能监听所有属性的变化,且在页面初始化时就会执行一次
// autorun 需要导入
import { makeAutoObservable, autorun } from "mobx";
class Counter {
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
value = 0;
increase() {
this.value++;
}
}
// 因 autorun 函数内需要使用到实例的属性,需先将实例存入变量 counter
const counter = new Counter();
autorun(() => {
//任一响应式属性变化时,都会执行,在页面初始化时,也会执行
console.log("counter.value的值为", counter.value);
});
export default counter;
reaction
与 vue 的 watch 概念相同,可精准指定要监听的属性,在属性变化时才执行处理函数(可以获取到新值和旧值),再页面初始化时,不会执行。
// reaction 需要导入
import { makeAutoObservable, reaction } from "mobx";
class Counter {
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
value = 0;
increase() {
this.value++;
}
}
// 因 reaction 函数内需要使用到实例的属性,需先将实例存入变量 counter
const counter = new Counter();
reaction(
// 第1个参数为要监听的属性
() => counter.value,
// 第2个参数为响应函数
(newValue, oldValue) => {
//仅在 value 属性变化时执行,在页面初始化时,不会执行
console.log("counter.value的旧值为", oldValue);
console.log("counter.value的新值为", newValue);
}
);
export default counter;
moxb 处理异步
异步执行的代码,需放入 runInAction 函数中(否则会有需在 action 中修改状态的提示)
// runInAction 需要导入
import { makeAutoObservable, runInAction } from "mobx";
class Counter {
constructor() {
makeAutoObservable(this, {}, { autoBind: true });
}
value = 0;
increase() {
setTimeout(() => {
// 异步执行的代码
runInAction(() => {
this.value++;
});
}, 1000);
}
}
export default new Counter();
moxb 模块化
当 store 设计的类比较多时,为了方便使用,可以将其模块化为一个 store 中,方便页面的导入和使用。
1. 将分散的store,全部放入RootStore
新建文件 src/store/index.js
import { createContext, useContext } from "react";
// 导入要统一管理的Store
import user from "./User.js";
import counter from "./Counter.js";
// 将分散的store,全部放入RootStore
class RootStore {
user = user;
counter = counter;
}
const store = new RootStore();
// 创建上下文
const Context = createContext(store);
// 导出自定义hook函数 --- useStore
export default function useStore() {
// 返回 useContext
return useContext(Context);
}
2. 页面中导入后,解构赋值使用
import { observer } from "mobx-react-lite";
// 导入自定义 hook 函数useStore
import useStore from "./store/index.js";
const Demo = observer(() => {
// 解构赋值,获取到需要的 store
const { counter, user } = useStore();
return (
<>
<div>用户的登录状态为:{user.if_Login ? "已登录" : "未登录"}</div>
<div>计数器的值为:{counter.value}</div>
<button onClick={counter.increase}>+1</button>
</>
);
});
export default Demo;