微信小程序全局状态的深入讲解

前言

在微信小程序中,可以利用 App.js 的 globalData 作为中间桥梁,在 Page, Component 之间,包括页面与页面,页面与组件,组件与组件之间传递需要传递的信息。但是,我们不能及时的知道 globalData 下的变化,在新建小程序的官方的默认事例中,获取 UserInfo 这一网络操作有延迟的,为此写了很多不必要的代码。就连官方案例都存在这一情况,相信在开发中你也会遇到类似的情况。在本文中将介绍如何解决这一类问题。

需求分析

相信以下情况是我们在没有全局状态管理下常有的操作:

  • 在 Page,Component 的 OnLoad,Attached 两个生命周期钩子函数中,进行一些从 App 的 globalData 赋值一些已经存在的属性到页面或组件中的 data 中。
  • 在最开始就存在一些异步的网络请求,获取的数据用于全局,刚开始可能这个 globalData 还没有相关属性,直到请求成功,才把相关属性添加到 globalData,而这时 Page 的从 globalData 的赋值操作可能已经完成了,只不过是 undefined,为此需要进一步的判断再进行赋值到 Page,Component 中。如果只是一两个这个还说很简单的,但是多个页面,或者多个变量都需要赋值的话,我想你会拒绝并寻找偷懒的办法。
  • 一些在页面和组件从 globalData 赋值的变量不仅是用于判断、展示,我们可能还需要依据用户交互而改变变量的值,那么在其他页面,其他组件中同样的变量也需要统一改变。

以上情况我们可提出以下几点需求:

  1. 在页面,组件初始加载时,尽早的从 globalData 获取并赋值到页面,组件所需要的一些属性
  2. 及时的获取一些 globalData 某一属性的变化,并进行一些后续相关操作
  3. 在改变 Page,Component 的值的同时,其他页面,组件也进行一样的改变

下面是需求的原始代码

// app.js
App({
 globalData: {
  userInfo: null
 },
 onLaunch(){
  wx.getSetting({
   success: res => {
    if(res.authSetting['scope.userInfo']){
     wx.getUserInfo({
      success: res => {
       this.globalData.userInfo = res.userInfo
       // 需求2
       if (this.userInfoReadyCallback) {
        // 存在此回调函数,意味着 page 执行了 onLoad
        // 且没有获取到 userInfo 并赋值到 page 的 data 中
        // 执行此回调函数,赋值到相应的页面中
        this.userInfoReadyCallback(res)
       }
      }
     })
    }
   }
  })
 }
})
// Pages/index/index.js
const app = getApp()
Page({
 // ...
 onLoad(options){
  // 需求1
  const userInfo = app.globalData.userInfo
  userInfo && this.setData({useInfo})
  // 需求2
  // 如果没有获取到 app.globalData.userInfo
  // 意味还未执行 wx.getUserInfo 的回调函数
  // 给 app 添加响应的一个回调函数,绑定此时的 this 到回调函数
  userInfo || app.userInfoReadyCallback = res => {
   this.setData({
    userInfo: res.userInfo
   })
   delete app.userInfoReadyCallback
  }
 }
})

这是官方小程序案例的代码,我只做了一点修改,这里只是展示了需求 2 ,globalData 属性从无到有时执行页面设置的回调函数,并没有实现每一次都会执行回调函数,需求 3 的代码比较复杂,不在此展示。

我们可以思考,以上几点需求需要实现的,一定要有的代码有哪些。可以发现,需求 1 和需求 3 主要就是页面,组件初始化,和 globalData 属性被改变时都需要使用 this.setData 方法,只不过每次 this 的指向的实例不同。而需求 2 则是应该存在一个回调函数,且回调函数的 this 也应该指向相应的实例,在 globalData 属性被改变时执行这些回调函数。
从时间点来看,我们有两个,一个是页面,组件初始化,一个是 globalData 属性改变时,那么第一个时间点,我们可以考虑到小程序的生命周期的钩子函数,onLoad 和 attached,在这两个时间点执行 this.setData 的操作。而 globalData 属性的改变都是我们主动或者用户事件而产生的,就是可以看作这一操作是一个对 globalData 某个属性的事件,而这个事件发生后再去执行一些写好的回调函数。

从操作对象来看,基本都是页面和组件的实例 this,以及 app.globalData。

需求理论性总结

综上,我们可以在初始化时,进行自动的 this.setData(不用自己手动),和保存 this(用于事件执行时指向相应的实例),存储相应的回调函数为事件(事件就是未执行的函数),在需要时主动触发这个事件即可。那么可以看到,整个流程下来,我们需要一个横跨 app,page,component 之间的一个变量,用于劫持初始化的钩子函数,进行自动化赋值,存储相应的事件,暴露一个事件触发的接口。

纸上得来终觉浅,绝知此事要躬行

看到这里,相信你已经有一定的了解全局状态管理,那么到底如何实现呢?在这里,我要强调,如果你阅读此文后对此有一定的了解了,我说的思路,那么你一定要自己尝试实现出代码,不管是否好坏,总是比没有实现的好,在自己实现中也许有更多的收获。下面以上上面案例展示一下简单的实现代码,给没看太明白的一个思路。在下次我会写一遍相关代码实现的讲解,应该会有。

// app.js
class Store {
 constructor(app){
 this['event'] = {}
 this.app = app
 }
 autoSet(globalData, instance){
 const instanceData = {}
 for (let prop of globalData){
  instanceData[prop] = this.app.globalData[prop]
  const callBack = (newValue) => {
  instance.setData({[prop]: newValue})
  instance.watch[prop] && instance.watch[prop].call(instance, newValue)
  }
  this.addEvent(prop, callBack)
  instance.setData(instanceData)
  callBack(instanceData[prop])
  delete instance.watch
  delete instance.globalData
 }
 }
 addEvent(eventName, callBack){
 this.event[eventName] = this.event[eventName] || []
 this.event[eventName].push(callBack)
 }
 dispatch(eventName, newValue){
 this.app.globalData[eventName] = newValue
 this.event[eventName] && this.event[eventName].forEach(item => item(newValue))
 }
}

App({
 globalData: {
  userInfo: null
 },
 onLaunch(){
  // new 一个实例并保存到小程序 app 中,用于全局调用
  this.store = new Store(this)
  wx.getSetting({
   success: res => {
    if(res.authSetting['scope.userInfo']){
     wx.getUserInfo({
      success: res => {
       // 获取到 userInfo 后,触发事件
       this.store.dispatch('userInfo', res.userInfo)
      }
     })
    }
   }
  })
 }
})
// Pages/index/index.js
const app = getApp()
Page({
 // ...
 data: {
  userName: null
 },
 // globalData 数组用于自动赋值
 globalData: ['userInfo'],
 // 监听相应的 globalData 属性,设置回调函数
 watch: {
  userInfo(userInfo){
  console.log('userInfo 更新啦', this)
  this.setData({userName: userInfo.nickName})
  }
 },
 onLoad(options){
  // 传入此 globalData,和实例,设置该实例需要的 data,创建事件
  app.store.autoSet(this.globalData, this)
  // 其他你想做的...
 }
})

上面的代码并没有劫持钩子函数,只是额外在函数开始时执行了绑定函数,而且也没有页面销毁时,释放内存的操作。还是有许多可优化的地方,这些都留到下一次讲解。

总结

到此这篇关于微信小程序全局状态的文章就介绍到这了,更多相关小程序全局状态内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用watch在微信小程序中实现全局状态共享

    问题 在之前开发微信小程序的时候,获取用户信息.openid还有地理位置这些信息的时候,都是采用Promise的方式异步获取,但是这样的话在页面和App.js中都获取就可能造成请求重复的问题. 比如为了在每个页面都能获取到这些共享信息,都会选择在App.js中进行获取,然后在页面级进行获取,这两次获取的时间间隔较小时就可能导致前一个请求还未获取到数据,后一个请求就会再次进行获取,这样就产生了两次请求. 还有一个问题就是书写麻烦(虽然也能通过async await简化),比如 onLoad() {

  • 微信小程序全局状态的深入讲解

    前言 在微信小程序中,可以利用 App.js 的 globalData 作为中间桥梁,在 Page, Component 之间,包括页面与页面,页面与组件,组件与组件之间传递需要传递的信息.但是,我们不能及时的知道 globalData 下的变化,在新建小程序的官方的默认事例中,获取 UserInfo 这一网络操作有延迟的,为此写了很多不必要的代码.就连官方案例都存在这一情况,相信在开发中你也会遇到类似的情况.在本文中将介绍如何解决这一类问题. 需求分析 相信以下情况是我们在没有全局状态管理下常

  • 微信小程序全局数据共享和分包图文详解

    目录 引言 全局数据共享 安装 MobX 相关的包 创建Store实例 将 Store 中的成员绑定到页面中 在页面使用 Store 中的成员 将 Store 成员绑定到组件中 在组件中使用 Store 中的成员 分包 分包的项目构成: 分包的加载规则: 分包的体积限制: 创建分包 打包原则 分包的引用原则 独立分包 独立分包的引用原则 分包预下载 总结 引言 经过web前端开发的学习,相信大家对于前端开发有了一定深入的了解,今天我开设了微信小程序专栏,主要想从移动端开发方向进一步发展,而对于我

  • uniapp 实现微信小程序全局分享的示例代码

    目录 创建全局分享内容文件 引入并全局注册该文件 自定义页面分享内容  uniapp 实现微信小程序的全局转发给好友/分享到朋友圈的功能.主要使用 Vue.js 的 全局混入 概念. 下面直接上 实现步骤和代码: 创建全局分享内容文件 1.创建一个全局分享的 js 文件.示例文件路径为:@/common/share.js ,在该文件中定义全局分享的内容: export default { data() { return { // 默认的全局分享内容 share: { title: '全局分享的标

  • 微信小程序全局配置以及页面配置详解

    目录 全局配置 全局配置文件及常用配置项 全局配置—window 小程序窗口组成部分 了解window节点常用的配置项 设置导航栏的标题 设置导航栏的背景色 设置导航栏的标题颜色 全局开启下拉刷新功能 设置下拉刷新时窗口的背景色 设置下拉刷新时loading的样式 设置上拉触底的距离 全局配置—tabbar 什么是tabbar tabbar的6个组成部分 tabbar节点的配置项 每个tab项的配置选项 页面配置 页面配置文件的作用 页面配置和全局配置的关系 页面配置中常用的配置项 小结 全局配

  • 微信小程序全局文件的使用详解

    目录 全局文件 总结 我们前边两篇介绍了账号的申请.注册,工具的安装,云服务的开通.本篇我们介绍一下基础语法.介绍的方法呢我们会结合上微搭低代码的工具一起做个对比.因为低代码工具也产生了非常多的技术概念,但最终在发布成小程序的时候也是按照微信的规范去生成的,把微信开发者工具学会了也可以更深入的了解低代码的相关概念. 全局文件 小程序中是分为全局和页面级两部分.全局是在小程序的所有页面都有效,页面级是只在当前页面中生效.小程序根目录有三个文件app.js.app.json.app.wxss这三个就

  • 微信小程序全局配置之tabBar实战案例

    目录 全局配置 - tabBar 1. 什么是 tabBar 2. tabBar 的 6 个组成部分 3. tabBar 节点的配置项 4. 每个 tab 项的配置选项 全局配置 - 案例:配置 tabBar 1. 需求描述 2. 实现步骤 3. 步骤1 - 拷贝图标资源 4.步骤2 - 新建 3 个对应的 tab 页面 5. 步骤3 - 配置 tabBar 选项 6. 完整的配置代码 总结 全局配置 - tabBar 1. 什么是 tabBar tabBar 是移动端应用常见的页面效果, 用于

  • 微信小程序登录状态java后台解密

    一.登录流程图 二.微信小程序端 doLogin:function(callback = () =>{}){ let that = this; wx.login({ success:function(loginRes){ if(loginRes){ //获取用户信息 wx.getUserInfo({ withCredentials:true,//非必填 默认为true success:function(infoRes){ console.log(infoRes,'>>>'); //

  • 微信小程序如何根据不同用户切换不同TabBar(简单易懂!)

    目录 现有需求: 1全局.app.json 2.自定义custom-tab-bar 结果展示 总结 现有需求: 小程序用户有三种身份(公众.运维人员.领导),根据不同用户身份显示不同的tabbar 众所周知微信小程序全局文件app.json里面的"tabBar"里面的list只能放置2-5个,要想实现3个tabbar,必须得复用tabbar,三种身份都需要个人中心,剩下的是长列表(两个),表单,图表 刚好是5个,废话少说,上代码 代码有点长,建议仔细看一下 1全局.app.json t

  • 微信小程序MoxB实现全局状态管理流程详解

    目录 安装 MobX 创建 MobX Store 使用 MobX Store 在 Component 构造器中使用 在 Page 页面中使用 github 地址:https://github.com/wechat-miniprogram/mobx-miniprogram-bindings. 安装 MobX 在小程序根目录下执行 npm install --save mobx-miniprogram mobx-miniprogram-bindings 安装 mobx-miniprogram 和 m

  • 微信小程序的WXSS和全局、页面配置详细讲解

    目录 一,WXSS 1.1 rpx尺寸单位 1.2 样式导入@import 1.3 全局样式 补充:wxss的扩展-样式导入 二,全局配置 2.1 属性 三,页面配置 总结 一,WXSS 首先我们先介绍一下wxss,wxss是微信小程序独有的模板样式,它类似于web开发中的CSS,具备CSS大部分的功能,同时,它还拓展出了几个内容功能,接下来牛牛介绍一下新增的rpx尺寸单位以及样式导入@import. 1.1 rpx尺寸单位 rpx尺寸单位是微信独有的,主要用来解决屏适配问题.怎么回事呢?我们知

随机推荐