记录一下在微信小程序中的使用MobX做状态管理
文章目录
- 概述
- 安装与构建
- 目录建议
- 举个例子
- 异步 Actions(示例)
- 持久化(按需)
- 常见问题与排查
概述
MobX 是一个响应式状态管理库。微信小程序官方适配库 mobx-miniprogram(配合 mobx-miniprogram-bindings)可以让你在 Page/Component 中以最小侵入方式读写全局状态,并保持 UI 自动更新。
适用场景
- 会话/聊天跨页面共享状态(如 consultationId、登录态、网络状态)
- 多入口跳转,避免层层传参
- 表单/列表/筛选项在多个子组件之间同步
- 复杂页面拆分,降低 props 传递复杂度
安装与构建
- 安装依赖(项目根目录执行):
npm i mobx-miniprogram mobx-miniprogram-bindings --save
- 在微信开发者工具中:
- 菜单:工具 -> 构建 npm
- 勾选“使用 npm模块”
- 构建完成后重新编译项目
目录建议
- stores/ 下放置所有全局 Store(按领域划分:im-store、user-store、app-store 等)
- 每个 Store 文件只导出 observable 对象与 actions
举个例子
这里用我开发im用到的情况举个例子,
home.js
是订单列表页面(图1),点击会跳转到chat
聊天页面(图2),聊天页面里会把组件细化一点,然后有些自定义消息组件(图2里的电子处方、病历)里就需要用到最外层home里的consultationId(订单id)
,这时候如果一层一层传值会很屎,而且不好维护了,就需要用到状态管理了
示例:创建一个 IM Store(stores/im-store.js)
const { observable, action, computed } = require('mobx-miniprogram');const imStore = observable({// observable stateconsultationId: '',unreadCount: 0,isOnline: true,// computed getter(只读派生值)chatTitle: computed(function () {return this.consultationId ? `问诊 ${this.consultationId}` : '问诊';}),// actions(同步/异步均可)setConsultationId: action(function (id) {this.consultationId = id || '';}),clearConsultationId: action(function () {this.consultationId = '';}),setUnreadCount: action(function (n) {this.unreadCount = Number(n) || 0;}),setOnline: action(function (flag) {this.isOnline = !!flag;}),
});module.exports = { imStore };
在页面中绑定使用(pages/home/home.js)
//方式 A:直接 require Store 并调用 actions(简单直接)const { imStore } = require('../../stores/im-store.js');// 写入问诊IDimStore.setConsultationId(consultation.id);//方式 B:使用 mobx-miniprogram-bindings 提供的 createStoreBindings(推荐,自动解绑)const { createStoreBindings } = require('mobx-miniprogram-bindings');const { imStore } = require('../../stores/im-store.js');Page({onLoad() {this.storeBindings = createStoreBindings(this, {store: imStore,fields: ['consultationId', 'unreadCount', 'chatTitle'], // 自动映射到 this.dataactions: ['setConsultationId', 'setUnreadCount', 'clearConsultationId', 'setOnline'], // 绑定为 this.setConsultationId 等});},onUnload() {this.storeBindings && this.storeBindings.destroyStoreBindings();},// 示例:进入聊天前设置咨询IDenterChat(consultation) {this.setConsultationId(consultation.id);// ...继续跳转},});
在自定义组件中绑定使用(components/XXX/index.js)
const { createStoreBindings } = require('mobx-miniprogram-bindings');
const { imStore } = require('../../stores/im-store.js'); // 根据相对路径调整Component({lifetimes: {attached() {this.storeBindings = createStoreBindings(this, {store: imStore,fields: ['consultationId', 'chatTitle', 'isOnline'],actions: ['setConsultationId', 'clearConsultationId', 'setOnline'],});},detached() {this.storeBindings && this.storeBindings.destroyStoreBindings();},},methods: {useId() {// 读const id = this.data.consultationId;// 写this.setUnreadCount(0);}}
});
与聊天场景集成的实践
- 入口设置:在首页进入聊天前,将 consultationId 写入 Store。
imStore.setConsultationId(consultation.id);
- 组件兜底读取:在聊天子组件(如 CustomMessage)取不到 payload 中订单ID时,回退读取 imStore.consultationId。
const { imStore } = require('../../stores/im-store.js');const orderId = imStore.consultationId;
- 退出清理:在 chat 页面 onUnload 清理咨询ID(可选)。
imStore.clearConsultationId();
异步 Actions(示例)
- MobX 不限制异步,推荐将副作用放在 actions 内,保持状态更新的集中管理。
const { observable, action, runInAction } = require('mobx-miniprogram');
const request = require('../utils/request');const appStore = observable({loading: false,data: null,loadData: action(async function () {this.loading = true;try {const res = await request.get('/api/path');runInAction(() => {this.data = res.data || null;this.loading = false;});} catch (e) {runInAction(() => { this.loading = false; });}}),
});
持久化(按需)
- 简单持久化:在 actions 中同步写入 Storage
setConsultationId: action(function (id) {this.consultationId = id || '';try { wx.setStorageSync('consultationId', this.consultationId); } catch (e) {}}),
- 初始化时从 Storage 复原:
const saved = wx.getStorageSync('consultationId');if (saved) imStore.setConsultationId(saved);
常见问题与排查
-
未更新 UI
- 检查是否通过 actions 修改 state(不要直接赋值),或确保使用 createStoreBindings 绑定 fields
- 在页面/组件绑定后,确保 destroyStoreBindings 在生命周期销毁
-
路径错误/组件未能读取 Store
- 小程序相对路径请严格按所在文件位置调整(…/…/ 或 …/…/…/)
- 使用 require 的路径与 usingComponents 的路径不同,注意区分
-
构建 npm 后仍报错
- 确保项目开启“使用 npm模块”
- 删除 miniprogram_npm 后重新构建;或重启开发者工具
-
性能与颗粒度
- fields 中只绑定当前视图需要的字段,避免不必要的 setData
- 将复杂计算放到 computed,避免在模板中重复计算
-
与 TUIKit(IM SDK)协作
- 将 IM 登录态、当前会话 ID、网络状态放入 Store,监听 SDK 事件后统一更新 Store
- 消息组件读取 Store 以决定显示逻辑(如已读、提示语、外部参数)
最佳实践清单
- Store 只做“状态 + 纯动作(actions)”,UI 逻辑与跳转放到页面/组件
- 所有状态更新走 actions,避免分散更新导致难以追踪
- 通过 bindings 管理生命周期,减少手动清理
- 入口页面设置关键上下文(如 consultationId),子组件只读不写
- 对跨天/分钟粒度时间展示等派生逻辑,用 computed 或在 observer 中预处理
参考
- 官方库:mobx-miniprogram(状态)、mobx-miniprogram-bindings(Page/Component 绑定)
- 微信开发者工具文档:使用 npm 模块与构建流程