子組件全數載入前加上loading icon|Waiting for Multiple API Calls to Complete Before Rendering Vue Component
Published in
5 min readJun 28, 2024
也是provide, inject的應用
假設有一個頁面中包了好幾層的component,紅色框的view會打三個API並props給下面的子組件,深藍色的子組件收到紅色API資料後再打API,並傳遞給淺藍色子組件,淺藍色子組件再將資料emit給橘色子組件:
這時候整個頁面就會頓頓的,等待資料獲取的時間並繪成chart,所以我想要做成等待所有API完成後渲染組件前,先加上loading的遮罩。
實作
父組件定義componentsLoading唯一空物件(new Set()
),用來存取loading狀態,並且定義loading中跟loading完成的函式(addLoading
、removeLoading
)
<!-- App.vue 或主要父組件 -->
<template>
<div>
<div v-if="isLoading">
<loading-icon></loading-icon>
</div>
<div v-else>
<component-1></component-1>
<component-2></component-2>
<!-- 更多組件... -->
</div>
</div>
</template>
<script setup>
import { ref, provide, computed } from 'vue'
import LoadingIcon from './LoadingIcon.vue'
import Component1 from './Component1.vue'
import Component2 from './Component2.vue'
const componentsLoading = ref(new Set()) // {}
const addLoading = (componentId) => {
componentsLoading.value.add(componentId) //{componentId}
}
const removeLoading = (componentId) => {
componentsLoading.value.delete(componentId)
}
// 如果componentsLoading內還有東西就代表還在load
const isLoading = computed(() => componentsLoading.value.size > 0)
provide('loadingManager', {
addLoading,
removeLoading,
})
</script>
利用porvide/inject將loadingManager方法傳遞給子組件,子組件利用方法更新loading狀態
vue
Copy
<!-- Component1.vue -->
<template>
<div>
<!-- 組件內容 -->
</div>
</template>
<script setup>
import { inject, onMounted } from 'vue'
const { addLoading, removeLoading } = inject('loadingManager')
onMounted(async () => {
const componentId = 'component1'
addLoading(componentId) // 剛載入頁面準備fetchData前先加上loading狀態
try {
// 執行 API 請求
await fetchData()
} catch (error) {
console.error('Error in Component1:', error)
} finally {
removeLoading(componentId) // 完成即移除
}
})
async function fetchData() {
// API
}
</script>
每一個子組件都做一樣的事情
父組件的isLoading會隨時抓取狀態,直到componentsLoading.value變回空物件,isLoading才會變成false,取消loading狀態並把loading icon移除,呈現載入好的頁面。