當(dāng)前位置:首頁 >  站長 >  編程技術(shù) >  正文

微信小程序全局狀態(tài)的深入講解

 2021-03-18 17:25  來源: 腳本之家   我來投稿 撤稿糾錯(cuò)

  域名預(yù)訂/競價(jià),好“米”不錯(cuò)過

這篇文章主要介紹了微信小程序全局狀態(tài)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

在微信小程序中,可以利用 App.js 的 globalData 作為中間橋梁,在 Page, Component 之間,包括頁面與頁面,頁面與組件,組件與組件之間傳遞需要傳遞的信息。但是,我們不能及時(shí)的知道 globalData 下的變化,在新建小程序的官方的默認(rèn)事例中,獲取 UserInfo 這一網(wǎng)絡(luò)操作有延遲的,為此寫了很多不必要的代碼。就連官方案例都存在這一情況,相信在開發(fā)中你也會遇到類似的情況。在本文中將介紹如何解決這一類問題。

需求分析

相信以下情況是我們在沒有全局狀態(tài)管理下常有的操作:

在 Page,Component 的 OnLoad,Attached 兩個(gè)生命周期鉤子函數(shù)中,進(jìn)行一些從 App 的 globalData 賦值一些已經(jīng)存在的屬性到頁面或組件中的 data 中。

在最開始就存在一些異步的網(wǎng)絡(luò)請求,獲取的數(shù)據(jù)用于全局,剛開始可能這個(gè) globalData 還沒有相關(guān)屬性,直到請求成功,才把相關(guān)屬性添加到 globalData,而這時(shí) Page 的從 globalData 的賦值操作可能已經(jīng)完成了,只不過是 undefined,為此需要進(jìn)一步的判斷再進(jìn)行賦值到 Page,Component 中。如果只是一兩個(gè)這個(gè)還說很簡單的,但是多個(gè)頁面,或者多個(gè)變量都需要賦值的話,我想你會拒絕并尋找偷懶的辦法。

一些在頁面和組件從 globalData 賦值的變量不僅是用于判斷、展示,我們可能還需要依據(jù)用戶交互而改變變量的值,那么在其他頁面,其他組件中同樣的變量也需要統(tǒng)一改變。

以上情況我們可提出以下幾點(diǎn)需求:

在頁面,組件初始加載時(shí),盡早的從 globalData 獲取并賦值到頁面,組件所需要的一些屬性

及時(shí)的獲取一些 globalData 某一屬性的變化,并進(jìn)行一些后續(xù)相關(guān)操作

在改變 Page,Component 的值的同時(shí),其他頁面,組件也進(jìn)行一樣的改變

下面是需求的原始代碼

// 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) {
// 存在此回調(diào)函數(shù),意味著 page 執(zhí)行了 onLoad
// 且沒有獲取到 userInfo 并賦值到 page 的 data 中
// 執(zhí)行此回調(diào)函數(shù),賦值到相應(yīng)的頁面中
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
// 意味還未執(zhí)行 wx.getUserInfo 的回調(diào)函數(shù)
// 給 app 添加響應(yīng)的一個(gè)回調(diào)函數(shù),綁定此時(shí)的 this 到回調(diào)函數(shù)
userInfo || app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo
})
delete app.userInfoReadyCallback
}
}
})

這是官方小程序案例的代碼,我只做了一點(diǎn)修改,這里只是展示了需求 2 ,globalData 屬性從無到有時(shí)執(zhí)行頁面設(shè)置的回調(diào)函數(shù),并沒有實(shí)現(xiàn)每一次都會執(zhí)行回調(diào)函數(shù),需求 3 的代碼比較復(fù)雜,不在此展示。

我們可以思考,以上幾點(diǎn)需求需要實(shí)現(xiàn)的,一定要有的代碼有哪些。可以發(fā)現(xiàn),需求 1 和需求 3 主要就是頁面,組件初始化,和 globalData 屬性被改變時(shí)都需要使用 this.setData 方法,只不過每次 this 的指向的實(shí)例不同。而需求 2 則是應(yīng)該存在一個(gè)回調(diào)函數(shù),且回調(diào)函數(shù)的 this 也應(yīng)該指向相應(yīng)的實(shí)例,在 globalData 屬性被改變時(shí)執(zhí)行這些回調(diào)函數(shù)。

從時(shí)間點(diǎn)來看,我們有兩個(gè),一個(gè)是頁面,組件初始化,一個(gè)是 globalData 屬性改變時(shí),那么第一個(gè)時(shí)間點(diǎn),我們可以考慮到小程序的生命周期的鉤子函數(shù),onLoad 和 attached,在這兩個(gè)時(shí)間點(diǎn)執(zhí)行 this.setData 的操作。而 globalData 屬性的改變都是我們主動或者用戶事件而產(chǎn)生的,就是可以看作這一操作是一個(gè)對 globalData 某個(gè)屬性的事件,而這個(gè)事件發(fā)生后再去執(zhí)行一些寫好的回調(diào)函數(shù)。

從操作對象來看,基本都是頁面和組件的實(shí)例 this,以及 app.globalData。

需求理論性總結(jié)

綜上,我們可以在初始化時(shí),進(jìn)行自動的 this.setData(不用自己手動),和保存 this(用于事件執(zhí)行時(shí)指向相應(yīng)的實(shí)例),存儲相應(yīng)的回調(diào)函數(shù)為事件(事件就是未執(zhí)行的函數(shù)),在需要時(shí)主動觸發(fā)這個(gè)事件即可。那么可以看到,整個(gè)流程下來,我們需要一個(gè)橫跨 app,page,component 之間的一個(gè)變量,用于劫持初始化的鉤子函數(shù),進(jìn)行自動化賦值,存儲相應(yīng)的事件,暴露一個(gè)事件觸發(fā)的接口。

紙上得來終覺淺,絕知此事要躬行

看到這里,相信你已經(jīng)有一定的了解全局狀態(tài)管理,那么到底如何實(shí)現(xiàn)呢?在這里,我要強(qiáng)調(diào),如果你閱讀此文后對此有一定的了解了,我說的思路,那么你一定要自己嘗試實(shí)現(xiàn)出代碼,不管是否好壞,總是比沒有實(shí)現(xiàn)的好,在自己實(shí)現(xiàn)中也許有更多的收獲。下面以上上面案例展示一下簡單的實(shí)現(xiàn)代碼,給沒看太明白的一個(gè)思路。在下次我會寫一遍相關(guān)代碼實(shí)現(xiàn)的講解,應(yīng)該會有。

// 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 一個(gè)實(shí)例并保存到小程序 app 中,用于全局調(diào)用
this.store = new Store(this)
wx.getSetting({
success: res => {
if(res.authSetting['scope.userInfo']){
wx.getUserInfo({
success: res => {
// 獲取到 userInfo 后,觸發(fā)事件
this.store.dispatch('userInfo', res.userInfo)
}
})
}
}
})
}
})

// Pages/index/index.js
const app = getApp()
Page({
// ...
data: {
userName: null
},
// globalData 數(shù)組用于自動賦值
globalData: ['userInfo'],
// 監(jiān)聽相應(yīng)的 globalData 屬性,設(shè)置回調(diào)函數(shù)
watch: {
userInfo(userInfo){
console.log('userInfo 更新啦', this)
this.setData({userName: userInfo.nickName})
}
},
onLoad(options){
// 傳入此 globalData,和實(shí)例,設(shè)置該實(shí)例需要的 data,創(chuàng)建事件
app.store.autoSet(this.globalData, this)
// 其他你想做的...
}
})

上面的代碼并沒有劫持鉤子函數(shù),只是額外在函數(shù)開始時(shí)執(zhí)行了綁定函數(shù),而且也沒有頁面銷毀時(shí),釋放內(nèi)存的操作。還是有許多可優(yōu)化的地方,這些都留到下一次講解。

總結(jié)

到此這篇關(guān)于微信小程序全局狀態(tài)的文章就介紹到這了,更多相關(guān)小程序全局狀態(tài)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

來源:腳本之家

鏈接:https://www.jb51.net/article/207572.htm

申請創(chuàng)業(yè)報(bào)道,分享創(chuàng)業(yè)好點(diǎn)子。點(diǎn)擊此處,共同探討創(chuàng)業(yè)新機(jī)遇!

相關(guān)標(biāo)簽
微信小程序

相關(guān)文章

熱門排行

信息推薦