场景:
在小程序中大家应该都有这样的场景,在onLaunch里用wx.login静默登录拿到code,再用code去发送请求获取token、用户信息等,整个过程都是异步的,然后我们在业务页面里onLoad去用的时候异步请求还没回来,导致没拿到想要的数据,以往要么监听是否拿到,要么自己封装一套回调,总之都挺麻烦,每个页面都要写一堆无关当前页面的逻辑。
直接上终极解决方案,公司内部已接入两年很稳定:
1.可完美解决异步问题
2.不污染原生生命周期,与onLoad等钩子共存
3.使用方便
4.可灵活定制异步钩子
5.采用监听模式实现,接入无需修改以前相关逻辑
6.支持各种小程序和vue架构
。。。
//为了简洁明了的展示使用场景,以下有部分是伪代码,请勿直接粘贴使用,具体使用代码看Github文档
//app.js
//globalData提出来声明
let globalData = {
// 是否已拿到token
token: '',
// 用户信息
userInfo: {
userId: '',
head: ''
}
}
//注册自定义钩子
import CustomHook from 'spa-custom-hooks';
CustomHook.install({
'Login':{
name:'Login',
watchKey: 'token',
onUpdate(token){
//有token则触发此钩子
return !!token;
}
},
'User':{
name:'User',
watchKey: 'userInfo',
onUpdate(user){
//获取到userinfo里的userId则触发此钩子
return !!user.userId;
}
}
}, globalData)
// 正常走初始化逻辑
App({
globalData,
onLaunch() {
//发起异步登录拿token
login((token)=>{
this.globalData.token = token
//使用token拿用户信息
getUser((user)=>{
this.globalData.user = user
})
})
}
})
//关键点来了
//Page.js,业务页面使用
Page({
onLoadLogin() {
//拿到token啦,可以使用token发起请求了
const token = getApp().globalData.token
},
onLoadUser() {
//拿到用户信息啦
const userInfo = getApp().globalData.userInfo
},
onReadyUser() {
//页面初次渲染完毕 && 拿到用户信息,可以把头像渲染在canvas上面啦
const userInfo = getApp().globalData.userInfo
// 获取canvas上下文
const ctx = getCanvasContext2d()
ctx.drawImage(userInfo.head,0,0,100,100)
},
onShowUser() {
//页面每次显示 && 拿到用户信息,我要在页面每次显示的时候根据userInfo走不同的逻辑
const userInfo = getApp().globalData.userInfo
switch(userInfo.sex){
case 0:
// 走女生逻辑
break
case 1:
// 走男生逻辑
break
}
}
})
具体文档和Demo见↓
Github:https://github.com/1977474741/spa-custom-hooks
祝大家用的愉快,记得star哦
兄弟,24年了,依旧优秀
大佬大佬,uniapp vue3的setup怎么实现呀,使用会报 onLoadXXX is not defined
可以不用globaldata? 可以用getStorageSync?
朋友圈分享不执行onLoadLogin的方法,onLoad正常;麻烦看看这个问题,急
楼主请问如果token 的过期或者不存在,怎么再次获取?app.js 只在加载第一次的时候运行,过期了或者获取失败,怎么处理呢
这个github链接打不开
请问uniapp+vue3 可以用?
现在支持原生小程序了吗?
系统提供的这个怎么样
app.userInfoReadyCallback
// 实例代码app.js
onLaunch() {
// 异步获取用户信息后
api.userInfo().then(res => {
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}).catch(err => {
})
}
// 在需要用用到的页面例如home.js
// 实例代码home.js
const app = getApp()
onLoad(options) {
this.setData({
isLogin: app.globalData.userInfo !== null
})
app.userInfoReadyCallback = res => {
console.log('触发:', res);
this.setData({
isLogin: app.globalData.userInfo !== null
})
}
},
}
分享一下我碰到的问题;已解决
我的问题是第一次编译的时候,userInfo对象数据更新,无法触发Page页面onLoadXX(XX代表监听函数的名字),第二次确可以。
我的猜想说一下,首先这个钩子函数应该是通过object.defineProperty进行监听对象的。当通过直接赋值的形式操作时(改变源对象的内存地址),那么钩子函数就监听不到了,所以就导致我这边onLoadXX(XX代表监听函数的名字)执行不了。下面是一个简单的demo
let number = 20; let obj = {a:1}; let obj1 = {a:2}; Object.defineProperty(obj,"b",{ get(){ console.log("有人读取了b属性") return number }, set(val){ number = val } }) obj = obj1; obj.b = 30; console.log(obj,number);// {a:2,b:30} (不再是响应式了) number=>20
改善方法
obj = obj1; //改为对对象进行合并,保留源对象的内存地址 obj = Object.assign(obj,obj1); obj.b = 30; console.log(obj,number);// {a:2,b:30} (不再是响应式了) number=>30
希望大家碰到这个问题能快速解决,反正我花了不少时间解决这个问题。如果条件有限的 作者可以加个判断,判断当前对象内存地址是否已经变化,然后告诉开发者。