文章目录
概述
MobX 是一个响应式状态管理库。微信小程序官方适配库 mobx-miniprogram(配合 mobx-miniprogram-bindings)可以让你在 Page/Component 中以最小侵入方式读写全局状态,并保持 UI 自动更新。
适用场景
- 会话/聊天跨页面共享状态(如 consultationId、登录态、网络状态)
- 多入口跳转,避免层层传参
- 表单/列表/筛选项在多个子组件之间同步
- 复杂页面拆分,降低 props 传递复杂度
安装与构建
- 安装依赖(项目根目录执行):
js
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)
js
const { observable, action, computed } = require('mobx-miniprogram');
const imStore = observable({
// observable state
consultationId: '',
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)
js
//方式 A:直接 require Store 并调用 actions(简单直接)
const { imStore } = require('../../stores/im-store.js');
// 写入问诊ID
imStore.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.data
actions: ['setConsultationId', 'setUnreadCount', 'clearConsultationId', 'setOnline'], // 绑定为 this.setConsultationId 等
});
},
onUnload() {
this.storeBindings && this.storeBindings.destroyStoreBindings();
},
// 示例:进入聊天前设置咨询ID
enterChat(consultation) {
this.setConsultationId(consultation.id);
// ...继续跳转
},
});
在自定义组件中绑定使用(components/XXX/index.js)
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。
js
imStore.setConsultationId(consultation.id);
- 组件兜底读取:在聊天子组件(如 CustomMessage)取不到 payload 中订单ID时,回退读取 imStore.consultationId。
js
const { imStore } = require('../../stores/im-store.js');
const orderId = imStore.consultationId;
- 退出清理:在 chat 页面 onUnload 清理咨询ID(可选)。
js
imStore.clearConsultationId();
异步 Actions(示例)
- MobX 不限制异步,推荐将副作用放在 actions 内,保持状态更新的集中管理。
js
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
js
setConsultationId: action(function (id) {
this.consultationId = id || '';
try { wx.setStorageSync('consultationId', this.consultationId); } catch (e) {}
}),
- 初始化时从 Storage 复原:
js
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 模块与构建流程