记录一下在微信小程序中的使用MobX做状态管理

文章目录

概述

MobX 是一个响应式状态管理库。微信小程序官方适配库 mobx-miniprogram(配合 mobx-miniprogram-bindings)可以让你在 Page/Component 中以最小侵入方式读写全局状态,并保持 UI 自动更新。

适用场景

  • 会话/聊天跨页面共享状态(如 consultationId、登录态、网络状态)
  • 多入口跳转,避免层层传参
  • 表单/列表/筛选项在多个子组件之间同步
  • 复杂页面拆分,降低 props 传递复杂度

安装与构建

  1. 安装依赖(项目根目录执行):
js 复制代码
   npm i mobx-miniprogram mobx-miniprogram-bindings --save
  1. 在微信开发者工具中:
    • 菜单:工具 -> 构建 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);

常见问题与排查

  1. 未更新 UI

    • 检查是否通过 actions 修改 state(不要直接赋值),或确保使用 createStoreBindings 绑定 fields
    • 在页面/组件绑定后,确保 destroyStoreBindings 在生命周期销毁
  2. 路径错误/组件未能读取 Store

    • 小程序相对路径请严格按所在文件位置调整(.../.../ 或 .../.../.../)
    • 使用 require 的路径与 usingComponents 的路径不同,注意区分
  3. 构建 npm 后仍报错

    • 确保项目开启"使用 npm模块"
    • 删除 miniprogram_npm 后重新构建;或重启开发者工具
  4. 性能与颗粒度

    • fields 中只绑定当前视图需要的字段,避免不必要的 setData
    • 将复杂计算放到 computed,避免在模板中重复计算
  5. 与 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 模块与构建流程
相关推荐
weixin_lynhgworld5 小时前
淘宝扭蛋机小程序:如何用游戏化思维提升电商转化率
游戏·小程序
小小王app小程序开发11 小时前
潮玩盲盒抽赏小程序玩法拆解:不同视角下的增长逻辑分析
小程序
星光一影11 小时前
Java版旅游系统/文旅系统/旅游助手/旅游攻略/公众号/小程序/app全套源码
java·小程序·开源软件·旅游·源代码管理
小小王app小程序开发11 小时前
盲盒小程序爬塔玩法深度细分:非技术视角下的运营细节拆解
小程序
游戏开发爱好者811 小时前
苹果iOS26系统升级:液态玻璃与智能功能全解析
macos·ios·小程序·uni-app·objective-c·cocoa·iphone
流***陌14 小时前
宠物寄养美容小程序前端功能解析:贴心照料宠物的全流程支撑
小程序·宠物
小小王app小程序开发17 小时前
任务悬赏小程序深度细分分析:非技术视角下的运营逻辑拆解
大数据·小程序
2501_9159184118 小时前
iOS 26 App 性能测试|性能评测|iOS 26 性能对比:实战策略
android·macos·ios·小程序·uni-app·cocoa·iphone
腾马科技1 天前
新版saas餐饮外卖小程序源码/微信/支付宝/抖音/扫码点餐/DIY装修/美团代付/全开源
微信小程序·小程序·点餐小程序