vue使用pinia實(shí)現(xiàn)全局無(wú)縫通信
前言
細(xì)數(shù) vue 中的數(shù)據(jù)通信方式,足足有十幾種,其中包括了父子互傳、兄弟互傳、隔代互傳、無(wú)關(guān)互傳,這十幾種方式每個(gè)都有其不同的語(yǔ)法,也就是說(shuō)我們需要根據(jù)這些組件的親戚關(guān)系選擇最合適的通信方式,我們無(wú)時(shí)無(wú)刻不在使用各種形式的參數(shù)傳遞。MD,像極了我們混亂的前端框架圈。
mqtt 協(xié)議
MQTT(Message Queuing Telemetry Transport,消息隊(duì)列遙測(cè)傳輸協(xié)議),是一種基于發(fā)布/訂閱(publish/subscribe)模式的“輕量級(jí)”通訊協(xié)議,該協(xié)議構(gòu)建于TCP/IP協(xié)議上,由IBM在1999年發(fā)布,適用于 低性能 的物聯(lián)網(wǎng)設(shè)備。
為什么要提mqtt呢,因?yàn)槲医酉聛?lái)要說(shuō)的和mqtt的通信方式息息相關(guān)。
首先簡(jiǎn)單介紹下 mqtt 這個(gè)東西,簡(jiǎn)單來(lái)說(shuō),它由三個(gè)部分組成:服務(wù)器(mqtt broker)、發(fā)布者(publisher)、訂閱者(subscriber)。其中發(fā)布者和訂閱者的身份通常是混合的,即一個(gè)用戶可以既是發(fā)布者又是訂閱者,當(dāng)發(fā)布消息時(shí),就是發(fā)布者,當(dāng)訂閱時(shí),就是訂閱者。
在發(fā)布消息時(shí),需要指定一個(gè)主題(topic),當(dāng)然,訂閱時(shí)也要指定一個(gè)主題。向某個(gè)主題發(fā)布消息時(shí),服務(wù)器會(huì)向所有訂閱這個(gè)主題的客戶端分發(fā)消息,當(dāng)訂閱者接收到時(shí),再根據(jù)消息內(nèi)容進(jìn)行它的下一步操作。
舉個(gè)例子,大概是:你(訂閱者)跟你媽(服務(wù)器)說(shuō),你弟弟(發(fā)布者)打游戲就告訴你,你好打他,然后你媽說(shuō)好的(訂閱成功),然后你弟弟打游戲(發(fā)布)的一瞬間,消息被你媽捕獲到了,然后告你了,你就成功打了你弟弟。
在上面的例子中,你通過(guò)訂閱消息,而后執(zhí)行了某些操作
發(fā)布訂閱思想
我們都知道,vue的雙向綁定原理是基于發(fā)布訂閱范式的(面試必備,擦,哥們)。想必你和我一樣,即使看了幾遍 vue 雙向綁定原理,還是對(duì)這個(gè)字眼不太理解,什么叫發(fā)布訂閱范式,發(fā)布訂閱在生活和編程中無(wú)處不在,是一種通俗意義,并不是編程專有術(shù)語(yǔ)。
其實(shí),vue 中的 watch / watchEffect 就是一個(gè)訂閱的表現(xiàn)。
watch(someValue,()=>{
// ...
})
上面的代碼,訂閱了 someValue 的值變化這一事件。但是好像這個(gè)例子中缺失了發(fā)布者,其實(shí)發(fā)布者是隱式存在的。
someValue = otherValue
此時(shí),這個(gè)js 語(yǔ)句就成了 發(fā)布者。
vue3 中的 watch 方法十分強(qiáng)大,它支持 深度監(jiān)聽(tīng)、監(jiān)聽(tīng)對(duì)象、對(duì)象下的單個(gè)屬性、多變量監(jiān)聽(tīng)等。
使用 watch 和 pinia 實(shí)現(xiàn)全局事件發(fā)布訂閱
通過(guò)上面的描述,不難發(fā)現(xiàn)用 watch 來(lái)監(jiān)聽(tīng) pinia 中的某些屬性,即可達(dá)到訂閱的效果,從而實(shí)現(xiàn)無(wú)障礙 傳參/通信,那么我們把所有涉及傳參和通信的場(chǎng)景都使用 pinia ,可行嗎?
我認(rèn)為可行,以這種方式傳參,完全不用考慮值從哪里來(lái),將要到哪里去。哪里用,就在哪里 watch。
適用場(chǎng)景
通過(guò)監(jiān)聽(tīng)全局變量變化從而執(zhí)行下一步操作的這種寫(xiě)法,聽(tīng)起來(lái)好像對(duì)性能影響很大,而實(shí)際上呢,pinia 對(duì)此已經(jīng)做了比較合適的機(jī)制,首先 Pinia store 依靠 pinia 實(shí)例在所有調(diào)用中共享同一個(gè) store 實(shí)例,你可以定義任意多的 store,而這些 store 不會(huì)單獨(dú)占用內(nèi)存,所以放心大膽的在多文件中創(chuàng)建 store 即可。
比如,現(xiàn)在有一個(gè) 全局的地圖組件mapbox,又有若干個(gè)小組件控制著地圖上的圖層的增刪改查,我們無(wú)需在每個(gè)組件中都向mapbox組件傳值、或者用ref獲取其實(shí)例,我們只需把需要的數(shù)據(jù)放到pinia中,然后在mapbox組件內(nèi)對(duì)其監(jiān)聽(tīng)。
// Mapbox.vue
watch(() => store.currGridData, (newValue) => {
renderGrid(newValue)
})
上面的代碼中監(jiān)聽(tīng)了store.currGridData數(shù)據(jù),當(dāng)其數(shù)據(jù)有變化時(shí),則重新渲染此數(shù)據(jù)。當(dāng)然,如果需要清除,就直接把此數(shù)據(jù)置空就好了,可以在監(jiān)聽(tīng)中新增空數(shù)據(jù)處理,或者在renderGrid函數(shù)中處理。
這么一來(lái),所有的組件,無(wú)論在什么位置,什么路徑,只要監(jiān)聽(tīng)某值的變化,即可做到類似傳值的效果。
潛在的問(wèn)題
內(nèi)存泄露
當(dāng)然世界上沒(méi)有十全十美的事情,這么干正常情況下對(duì)性能幾乎是沒(méi)有影響的,但一旦出現(xiàn)問(wèn)題,那將是致命的。雖然 pinia 的實(shí)例是單例的,但是引用卻不是,每新增一個(gè) 對(duì)store值的watch,就會(huì)新增一個(gè)對(duì)此值的引用,正常情況下,vue會(huì)主動(dòng)在頁(yè)面銷毀時(shí)移除這些 watch,但是如果 watch 放在了異步體內(nèi),則需要注意手動(dòng)移除它們,否則就會(huì)使這些內(nèi)存常駐,也就是內(nèi)存泄露。
死循環(huán)
完全依靠 watch 來(lái)執(zhí)行操作,會(huì)在不經(jīng)意間造成死循環(huán)或者棧溢出的問(wèn)題。舉個(gè)例子
watch(()=>store.someValue,()=>{
store.someValue = otherValue
})
如果otherValue的值是一個(gè)固定值,那么在下一次將不再進(jìn)入了,因?yàn)橹禌](méi)有再變化,但是如果值不是固定值,很容易看出來(lái),這個(gè) watch 實(shí)際上是一個(gè)死循環(huán),當(dāng)操作了store.someValue的值后,又會(huì)重新回到這個(gè)watch。要避免這個(gè)問(wèn)題也很簡(jiǎn)單,像通常的遞歸函數(shù)一樣,給他一個(gè)跳出的條件即可
watch(()=>store.someValue,(nv)=>{
if(nv == someValue) return
store.someValue = otherValue
})
不觸發(fā)問(wèn)題
當(dāng)監(jiān)聽(tīng)的某值不變化時(shí),watch 不會(huì)觸發(fā),這樣就會(huì)導(dǎo)致另一個(gè)問(wèn)題,如果依賴某個(gè)值的變化來(lái)做一些操作,而這個(gè)操作和這個(gè)值的變化又不是雙向耦合的,此時(shí)就會(huì)造成給某值賦值時(shí),不會(huì)觸發(fā) watch。
例如通過(guò)值goNewArea來(lái)使地圖跳轉(zhuǎn)到新的地區(qū)視角。
watch(()=>store.goNewArea,()=>{
map.flyTo({
// ...
})
})
比如有一個(gè)按鈕,會(huì)將其賦值為北京市,那么地圖正常跳轉(zhuǎn)到北京,如果此時(shí)我們通過(guò)拉動(dòng)地圖視角,使實(shí)際區(qū)域變成了上海市,此時(shí)再通過(guò)按鈕將其賦值為北京市時(shí),地圖將不會(huì)觸發(fā)跳轉(zhuǎn),因?yàn)?code>store.goNewArea沒(méi)有變化。
要解決這個(gè)問(wèn)題,則應(yīng)該給這個(gè)值一個(gè)置空。即:
watch(()=>store.goNewArea,()=>{
map.flyTo({
// ...
})
map.once('moveend',()=>{
store.goNewArea = ""
})
})
上面提到,這樣做會(huì)導(dǎo)致watch重復(fù)觸發(fā)死循環(huán)的問(wèn)題,所以還要再加一句:
watch(()=>store.goNewArea,(nv)=>{
if(nv == "") return
map.flyTo({
// ...
})
map.once('moveend',()=>{
store.goNewArea = ""
})
})
總結(jié)
使用 watch 配合 pinia 全局變量,來(lái)實(shí)現(xiàn)全局的事件控制,在一定意義上簡(jiǎn)化了開(kāi)發(fā)流程,說(shuō)實(shí)話,寫(xiě)起來(lái)非常爽,也非常清晰。但是一旦變量多起來(lái),相互影響的概論就會(huì)增大,管理龐大的 watch 們也是一項(xiàng)負(fù)擔(dān),你需要時(shí)刻注意不要內(nèi)存溢出、死循環(huán)。
總之這種寫(xiě)法的靈活性拉滿了,但是需要非常清晰的思路和對(duì)業(yè)務(wù)深刻的理解,才能游刃有余。
到此這篇關(guān)于vue使用pinia實(shí)現(xiàn)全局無(wú)縫通信的文章就介紹到這了,更多相關(guān)vue pinia全局無(wú)縫通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3使用mpegts.js播放FLV視頻的配置和遇到的坑解決辦法
mpegts.js是在HTML5上直接播放MPEG-TS/FLV流的播放器,針對(duì)低延遲直播優(yōu)化,這篇文章主要給大家介紹了關(guān)于Vue3使用mpegts.js播放FLV視頻的配置和遇到的坑,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-05-05
前端虛擬滾動(dòng)列表實(shí)現(xiàn)代碼(vue虛擬列表)
前端的性能瓶頸那就是頁(yè)面的卡頓,當(dāng)然這種頁(yè)面的卡頓包含了多種原因,下面這篇文章主要給大家介紹了關(guān)于前端虛擬滾動(dòng)列表實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06
Vee-validate 父組件獲取子組件表單校驗(yàn)結(jié)果的實(shí)例代碼
vee-validate 是為 Vue.js 量身打造的表單校驗(yàn)框架,允許您校驗(yàn)輸入的內(nèi)容并顯示對(duì)應(yīng)的錯(cuò)誤提示信息。這篇文章主要介紹了Vee-validate 父組件獲取子組件表單校驗(yàn)結(jié)果 ,需要的朋友可以參考下2019-05-05
vue3前端axios請(qǐng)求報(bào)錯(cuò)network錯(cuò)誤的解決辦法
在使用Axios進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),遇到“Network?Error”報(bào)錯(cuò)可能是由多種原因?qū)е碌?這篇文章主要介紹了vue3前端axios請(qǐng)求報(bào)錯(cuò)network錯(cuò)誤的解決辦法,需要的朋友可以參考下2025-08-08
vue項(xiàng)目中的數(shù)據(jù)變化被watch監(jiān)聽(tīng)并處理
這篇文章主要介紹了vue項(xiàng)目中的數(shù)據(jù)變化被watch監(jiān)聽(tīng)并處理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
vue實(shí)現(xiàn)元素拖動(dòng)并互換位置的實(shí)現(xiàn)代碼
在使用Vue的場(chǎng)景下,需要實(shí)現(xiàn)對(duì)元素進(jìn)行拖動(dòng)交換位置,接下來(lái)通過(guò)本文給大家介紹vue實(shí)現(xiàn)元素拖動(dòng)并互換位置的實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-09-09
詳解如何創(chuàng)建基于vite的vue項(xiàng)目
vite 這個(gè)是尤大開(kāi)發(fā)的新工具,目的是以后替代webpack,下面這篇文章主要給大家介紹了關(guān)于如何創(chuàng)建基于vite的vue項(xiàng)目的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11
ElementUI動(dòng)態(tài)渲染el-table的實(shí)現(xiàn)過(guò)程
在前端開(kāi)發(fā)中,表格是不可或缺的一部分,無(wú)論是數(shù)據(jù)展示、數(shù)據(jù)錄入,還是數(shù)據(jù)分析,表格都扮演著重要的角色,而在Vue.js生態(tài)系統(tǒng)中,ElementUI提供了一個(gè)強(qiáng)大且靈活的表格組件——el-table,本文將帶你深入了解如何使用ElementUI動(dòng)態(tài)渲染el-table,并詳細(xì)探討其原理及實(shí)現(xiàn)過(guò)程2024-08-08

