小程序 页面级别mobx方案

127 阅读2分钟

PS:最近公司有一个重构的需求,一个相对独立的功能模块,早先由于各种原因写的很乱,尤其是参数传递过多、过深,triggerEvent过多导致难以理解,同时难以扩展需求,故进行重构

经调研决定采用数据共享方案mobx实现统一状态管理。

包层面:通过自己封装一层,对外暴漏api

const {
  storeBindingsBehavior,
  createStoreBindings,
  ComponentWithStore,
  BehaviorWithStore
} = require("./miniprogram-bindings/index");

// 获取当前 store
function getStore() {
  const appInstance = getApp()
  const globalData = appInstance.globalData;
  const storeKey = globalData.currentKey;
  return {
    storeKey,
    store: globalData[storeKey],
  };

调研阶段不确定使用效果如何。这样封装一层便于导入使用,而且方便做一些自定义的东西。
module.exports = {
  ComponentWithStore,
  storeBindingsBehavior,
  BehaviorWithStore,
  createStoreBindings,
  getStore,
};

首先一个问题: 小程序与vue不太一样,其状态管理只能是页面级的。每个页面相当于一个实例,所以mobx只能绑到页面级别。

这样引出了一个问题,一个功能组件可能被多个不同页面引用(不采用props方案)。在组件级别如何取到属于当前页面的store呢。想了一种方案如下:


  const customPageKey = "practice";
  const storeKey = customPageKey + randomString(6);

  const appInstance = getApp();
  appInstance.globalData[storeKey] = store;
  appInstance.globalData.currentKey = storeKey;
}

在每个页面 创建store实例对象的时候,生成一个全局唯一key作为健值把store存到appInstance.globalData上。并且把当前页面key存到全局。同时 每个页面onLoad时,都要把自己的key存到全局,其下组件通过getStore()拿到属于当前页面的key。(ps:因为组件属于页面,展示组件必定先有页面,页面初始化之初写入key,组件拿到的必是当前页面key和store)

这一步引出了一个大问题:

会发现同一个组件先在A页面使用了,跳转到B页面使用,它的actions方法始终不更新,created执行正常,其余也都正常,试了很多办法,也查了很多资料。证实小程序自定义组件是有缓存的,会对实例进行缓存导致没有重新绑定。(ps:大多场景组件都在attached进行了操作,确实是忽略了缓存因素走了弯路)。

解决上,通过封装了一层组件,自定义behavior在组件更新时,手动的刷新绑定。

成果上: 采用mobx重构后,无论多深的组件,只需通过store即可获取一些所需的参数。避免了props满天飞的复杂场景,在接口、功能拓展上极大优化了开发复杂度。