Vue3頁(yè)面數(shù)據(jù)加載延遲的問題分析和解決方法
1. 問題描述
在 Vue 3 的項(xiàng)目中,當(dāng)我們使用響應(yīng)式數(shù)據(jù)(如 ref 或 computed)來管理頁(yè)面狀態(tài)時(shí),可能會(huì)遇到由于接口數(shù)據(jù)加載延遲,導(dǎo)致頁(yè)面初始渲染時(shí)數(shù)據(jù)尚未獲取完成的問題。這會(huì)導(dǎo)致頁(yè)面在數(shù)據(jù)未更新的情況下提前渲染出來,從而產(chǎn)生顯示錯(cuò)誤或不完整的內(nèi)容。
針對(duì)此問題簡(jiǎn)單分析下原因和解決方法。
1、Vue 響應(yīng)式系統(tǒng)的工作機(jī)制
Vue 3 的響應(yīng)式系統(tǒng)基于 Proxy 實(shí)現(xiàn),通過 reactive、ref 或 computed 等 API 來響應(yīng)數(shù)據(jù)的變化。當(dāng)數(shù)據(jù)變化時(shí),Vue 會(huì)自動(dòng)重新渲染與這些數(shù)據(jù)綁定的 DOM 元素。但是,如果數(shù)據(jù)在初始渲染時(shí)為空或未加載,Vue 會(huì)將頁(yè)面渲染為初始狀態(tài),直到數(shù)據(jù)加載完畢并觸發(fā)響應(yīng)式更新。
假設(shè)存在一個(gè) ref 類型的響應(yīng)式數(shù)據(jù) data,在組件加載時(shí)該數(shù)據(jù)為空,且需要從接口獲取數(shù)據(jù)。
import { defineComponent, ref, onMounted } from 'vue'; export default defineComponent(() => { const data = ref(''); // 初始值為空 onMounted(async () => { // 模擬延遲獲取接口數(shù)據(jù) await new Promise((resolve) => setTimeout(resolve, 3000)); data.value = '已加載的數(shù)據(jù)'; // 設(shè)置接口返回的數(shù)據(jù) }); return () => ( <div> <p>{data.value ? data.value : '加載中...'}</p> </div> ); });
效果:組件渲染時(shí),data.value 為 null,所以會(huì)展示 加載中...,3秒之后,數(shù)據(jù)才被加載,頁(yè)面才會(huì)更新。
2、異步加載時(shí)的頁(yè)面閃爍與內(nèi)容不一致
接口請(qǐng)求需要時(shí)間,頁(yè)面初始渲染會(huì)先使用默認(rèn)數(shù)據(jù)或空值進(jìn)行渲染。數(shù)據(jù)加載完成后,頁(yè)面可能會(huì)發(fā)生更新,導(dǎo)致用戶看到的內(nèi)容短暫不一致或發(fā)生閃爍。
2. 解決方法
1、手動(dòng)觸發(fā)頁(yè)面更新
如果響應(yīng)式數(shù)據(jù)未觸發(fā)渲染,可以嘗試使用 nextTick 或通過直接重新賦值觸發(fā)更新。
import { defineComponent, ref, nextTick } from 'vue'; export default defineComponent(() => { const message = ref<string | null>(null); const updateMessage = async () => { setTimeout(() => { message.value = 'Hello, Vue!'; nextTick(() => { console.log('視圖已更新'); }); }, 1000); }; updateMessage(); return () => ( <div> <p>{message.value || '加載中...'}</p> </div> ); });
2、使用占位符避免初次渲染閃爍
在初次加載數(shù)據(jù)前,渲染占位符或骨架屏,確保用戶體驗(yàn)。
import { defineComponent, ref } from 'vue'; export default defineComponent(() => { const loading = ref(true); const data = ref<string | null>(null); setTimeout(() => { data.value = '接口數(shù)據(jù)加載完成'; loading.value = false; }, 2000); return () => ( <div> {loading.value ? ( <p>加載中...</p> ) : ( <p>數(shù)據(jù):{data.value}</p> )} </div> ); });
3、異步邏輯補(bǔ)充響應(yīng)式支持
在異步接口中獲取數(shù)據(jù)后,直接調(diào)用 Vue 提供的響應(yīng)式 API 來強(qiáng)制觸發(fā)更新。
import { defineComponent, reactive } from 'vue'; export default defineComponent(() => { const state = reactive({ list: [] as string[], }); const fetchList = async () => { setTimeout(() => { state.list = ['Item 1', 'Item 2', 'Item 3']; // 確保重新賦值觸發(fā)響應(yīng)式 }, 1000); }; fetchList(); return () => ( <div> <ul> {state.list.length > 0 ? state.list.map((item) => <li>{item}</li>) : '加載中...'} </ul> </div> ); });
4、使用 watch 監(jiān)聽數(shù)據(jù)變化并在更新時(shí)執(zhí)行額外的邏輯。
import { defineComponent, ref, watch } from 'vue'; export default defineComponent(() => { const data = ref<string | null>(null); watch(data, (newVal) => { console.log('數(shù)據(jù)已更新:', newVal); }); setTimeout(() => { data.value = 'Hello, World!'; }, 1000); return () => ( <div> <p>{data.value || '加載中...'}</p> </div> ); });
關(guān)鍵點(diǎn):
1、確保使用響應(yīng)式對(duì)象或變量,并在賦值時(shí)考慮 Vue 響應(yīng)式系統(tǒng)的特點(diǎn)。
2、如果頁(yè)面更新異常,可使用 nextTick 或 watch 來確保觸發(fā)渲染。
3、提前處理數(shù)據(jù)加載占位,優(yōu)化用戶體驗(yàn)。
3. 新的疑惑
可能會(huì)出現(xiàn)一個(gè)困惑:
為什么使用 ref 的響應(yīng)式數(shù)據(jù)在頁(yè)面渲染后獲取后,不直接更新頁(yè)面,而必須放在 watch 里面呢?
ref 的響應(yīng)式數(shù)據(jù)本身是具有更新頁(yè)面的能力的,但如果在頁(yè)面渲染后會(huì)發(fā)現(xiàn)數(shù)據(jù)更新未觸發(fā)視圖變化,可能是由于以下幾個(gè)原因?qū)е碌模?/p>
1、頁(yè)面未綁定響應(yīng)式數(shù)據(jù)
如果在模板或渲染函數(shù)中,數(shù)據(jù)未綁定到 DOM 或組件中,Vue 的響應(yīng)式系統(tǒng)就不會(huì)知道該數(shù)據(jù)的變化需要觸發(fā)視圖更新。
import { defineComponent, ref } from 'vue'; export default defineComponent(() => { const data = ref<string | null>(null); setTimeout(() => { data.value = '新數(shù)據(jù)'; // 更新數(shù)據(jù) }, 2000); return () => ( <div> {/* 沒有直接使用 data.value */} <p>數(shù)據(jù)加載完成!</p> </div> ); });
示例中,雖然 data.value 被更新了,但它并未綁定到頁(yè)面上,因此頁(yè)面沒有感知到需要重新渲染。為了解決這個(gè)問題,需要確保將數(shù)據(jù)綁定到視圖中:
import { defineComponent, ref } from 'vue'; export default defineComponent(() => { const data = ref<string | null>(null); setTimeout(() => { data.value = '新數(shù)據(jù)'; // 更新數(shù)據(jù) }, 2000); return () => ( <div> <p>{data.value || '加載中...'}</p> </div> ); });
2、數(shù)據(jù)賦值操作不當(dāng)
當(dāng)從接口獲取數(shù)據(jù)后,不正確的賦值操作,也可以造成響應(yīng)式數(shù)據(jù)未更新導(dǎo)致的。
3、為什么放到 watch 中能解決?
watch 的作用是監(jiān)聽響應(yīng)式數(shù)據(jù)的變化并執(zhí)行相應(yīng)的副作用邏輯。即使數(shù)據(jù)更新沒有直接綁定到視圖,watch 可以保證代碼邏輯在數(shù)據(jù)變化時(shí)被觸發(fā)。
import { defineComponent, ref, watch } from 'vue'; export default defineComponent(() => { const data = ref<string | null>(null); setTimeout(() => { data.value = 'Hello, Vue!'; }, 2000); // 監(jiān)聽數(shù)據(jù)變化并更新額外邏輯 watch(data, (newVal) => { console.log('數(shù)據(jù)更新為:', newVal); }); return () => ( <div> <p>{data.value || '加載中...'}</p> </div> ); });
原因:watch 主動(dòng)監(jiān)聽數(shù)據(jù)變化,無論視圖是否綁定響應(yīng)式數(shù)據(jù),watch 都會(huì)響應(yīng)數(shù)據(jù)變化并執(zhí)行邏輯。
以上就是Vue3頁(yè)面數(shù)據(jù)加載延遲的問題分析和解決方法的詳細(xì)內(nèi)容,更多關(guān)于Vue3頁(yè)面數(shù)據(jù)加載延遲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
element滾動(dòng)條組件el-scrollbar的使用詳解
本文主要介紹了element滾動(dòng)條組件el-scrollbar的使用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04vue父組件向子組件動(dòng)態(tài)傳值的兩種方法
這篇文章主要介紹了vue父組件向子組件動(dòng)態(tài)傳值的兩種方法 ,需要的朋友可以參考下2017-11-11vue3中關(guān)于i18n字符串轉(zhuǎn)義問題
這篇文章主要介紹了vue3中關(guān)于i18n字符串轉(zhuǎn)義問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04詳解在vue中如何實(shí)現(xiàn)屏幕錄制與直播推流功能
屏幕錄制和直播推流是現(xiàn)代Web應(yīng)用中常用的功能,Vue作為一種流行的JavaScript框架,提供了一些工具和庫(kù),可以方便地實(shí)現(xiàn)屏幕錄制和直播推流功能,本文將介紹如何在Vue中進(jìn)行屏幕錄制和直播推流,需要的朋友可以參考下2024-01-01Vue?props傳入function時(shí)的this指向問題解讀
這篇文章主要介紹了Vue?props傳入function時(shí)的this指向問題解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01Vue.set()和this.$set()使用和區(qū)別
我們發(fā)現(xiàn)Vue.set()和this.$set()這兩個(gè)api的實(shí)現(xiàn)原理基本一模一樣,那么Vue.set()和this.$set()的區(qū)別是什么,本文詳細(xì)的介紹一下,感興趣的可以了解一下2021-06-06vue3使用vueup/vue-quill富文本、并限制輸入字?jǐn)?shù)的方法處理
這篇文章主要介紹了vue3使用vueup/vue-quill富文本、并限制輸入字?jǐn)?shù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03Vue 電商后臺(tái)管理項(xiàng)目階段性總結(jié)(推薦)
這篇文章主要介紹了Vue 電商后臺(tái)管理項(xiàng)目階段性總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08