官方文档 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;