当前位置: 首页 > news >正文

基于Mobx的多页面小程序的全局共享状态管理实践

what

  • 名字很长很绕靠口,总的来说,本文是对开发小程序过程中使用mobx的一个总结。

  • 状态管理,相比大家也很熟悉,顾名思义,是对前端页面繁复的状态进行管理,在此,我也不过多赘述。

  • 所以虽然是是用在小程序上,不过我想对于WebApp的状态管理,也有这么一丢丢启发。

why

  • 为什么要进行状态管理?
    现在的小程序俨然是Hybrid App,又像是PWA,但当然也是一个WebApp,更不用说他的语法和vue略微有这么一丢丢相似。有reactvue的实践在前,所以对于小程序上那么多的页面状态和数据缓存,势必也要引入一个状态管理工具

  • 为什么是mobx
    方便,快捷,学习成本低,当然也是仁者见仁智者见智

how

  1. 在小程序中引入mobx
    在这里我使用了wechat-weapp-mobx这个库。在./libs目录下放入mobx.jsobserver.js这两个库,同时在./store目录下新建store.js用于存放全局状态。

  2. 建立store
    由于小程序中不支持@decorate装饰器,所以采用了extendObservable的写法。另外,小程序支持import语法和require语法。我比较喜欢import语法,你们呢?我认为在action中不该写入复杂逻辑代码,保持简洁性和可复用性,你们怎么看

    // store.js
    // 引入必须的库
    const mobx = require('../libs/mobx');
    const extendObservable = require('../libs/mobx').extendObservable;
    const computed = require('../libs/mobx').computed;
    const toJS = require('../libs/mobx').toJS;
    
    let store = function () {
      extendObservable(this, {
    
        // observable data
        players: [],
    
        // computed data
        get count() {
          return this.players.length;
        }
      });
    
      // action
      this.addPlayer = name => {
        let len = this.count;    //此处调用computed data
        let id = len === 0 ? 1 : this.players[len - 1].id + 1;
        this.players.push(new player(name, id));
      }
    }
    
    export default store;
    
  3. 全局引入store
    众所周知,使用mobxstore要使用new store(),如果我们想全局调用,势必不可能在每个页面都new一个sotre,因为这样的话每个页面的store都是一个全新的store。在这里,我在app.js里引入store,并挂载在全局变量globalData下。另外,小程序中不支持路径的省略。

    //app.js
    const observer = require('./libs/observer').observer;
    import store from './stores/index';  // 小程序中不支持省略调用
    
    App(observer({
      onLaunch: function () {
      },
      globalData: {
        store: new store()
      }
    }))
  4. 在pages里调用全局的store
    可以同时使用内置的data进行双向绑定哦

    // index.js
    const observer = require('../../libs/observer').observer;
    
    let app = getApp();
    Page(observer({
      data: {
        mes: 'hello jim green'
      },
      props: {
        store: app.globalData.store
      },
    }))
  5. 在页面中调用store

    <view class="players-list">
      <view class="players-item" wx:for="{{props.store.players}}" wx:key="{{item.id}}">    // 调用observable data
        <text class="players">{{item.id}}:{{item.name}}</text>
      </view>
      <view>{{props.sotre.count}}</view>    //  调用computed data
    </view>
  6. 更新多个页面的store
    问题来了,这个时候,多个页面的store还是独立的,如何全部更新呢?答案就是在onShowonHide或者onUnload这三个生命周期函数中跟新全局的store

    onShow: function() {    // 显示时更新本页面store
      this.props.store = app.globalData.store
    },
    onHide: function() {   // 隐藏时更新全局store
      app.globalData.store = this.props.store;
    },
    onUnload: function() {    // 页面跳转返回时更新全局store
      app.globalData.store = this.props.store;
    },
  7. store和localStorage的长效存储
    考虑到网络还有程序崩溃的问题,我将store存储在localStorage中以便恢复,我在index.jsonLoad中调用get storage,在onHideset storage。由于toJS方法返回了一个不支持[Symbol.iterator]()的对象,所以在store里进行了如下设置

    // index.js
    onLoad: function () {
      let store = wx.getStorageSync('store');
      if(store) {
        this.props.store.formStorageToStore(store);
      }
    },
    onHide: function () {
      
      let store =this.props.store.currentStore;
      wx.setStorageSync('store', store)
    },
    
    // store.js
      get currentStore() {
        let {players,games,currentGame,hidden,filter} = toJS(this);
        return {players,games,currentGame,hidden,filter};
      }
      this.formStorageToStore = ({players,games,currentGame,hidden,filter}) => {
        this.players = players;
        this.games = games;
        this.currentGame = currentGame;
        this.hidden = hidden;
        this.filter = filter;
      }

others

讲点其他

  • 本项目的示例小程序地址weapp-bmscore,欢迎各位老铁点个关注666

相关文章:

  • Jsoup教程,jsoup开发指南,jsoup中文使用手册,jsoup中文文档
  • RabbitMQ 知识总结
  • Python多个装饰器的顺序 转载
  • springboot使用Thymedef模板引擎环境配置
  • Linux系统的pxe自动化运维部署
  • ftp--pureftpd1.0.46
  • 深入JVM分析spring-boot应用hibernate-validator
  • 正确的Kado ED「永遠のこたえ」
  • 最简单的基于FFmpeg的移动端样例:IOS 视频解码器
  • python全栈开发从入门到放弃之递归函数的调用
  • 选好网络管理工具 “0掉线”也并非不可能
  • 大数据市场蕴含万亿级别巨大商机
  • HBase – Memstore Flush深度解析
  • 什么是工程师文化?
  • 大数据将颠覆润滑管理模式
  • 【EOS】Cleos基础
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • iOS小技巧之UIImagePickerController实现头像选择
  • JavaScript的使用你知道几种?(上)
  • Laravel Mix运行时关于es2015报错解决方案
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • nodejs:开发并发布一个nodejs包
  • springMvc学习笔记(2)
  • TypeScript实现数据结构(一)栈,队列,链表
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 编写高质量JavaScript代码之并发
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 工作中总结前端开发流程--vue项目
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 区块链分支循环
  • 使用 Docker 部署 Spring Boot项目
  • 算法-插入排序
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 延迟脚本的方式
  • Android开发者必备:推荐一款助力开发的开源APP
  • C# - 为值类型重定义相等性
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (2)nginx 安装、启停
  • (52)只出现一次的数字III
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (二)学习JVM —— 垃圾回收机制
  • (理论篇)httpmoudle和httphandler一览
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)
  • (转)Google的Objective-C编码规范
  • ***详解账号泄露:全球约1亿用户已泄露
  • .net 调用php,php 调用.net com组件 --
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .sh 的运行