Suspense,這也是新觀念~
但應該跟異步有點關係吧?
快來看看吧!
每天看一篇文章~希望能持續下去啊!
大家會想什麼內容呢?快來留言吧
<Suspense>
是一個實驗性功能。它不保證會達到穩定狀態,並且 API 在達到穩定狀態之前可能會發生變化。
<Suspense>
是一個內建組件,用於在組件樹中協調異步依賴。它可以在等待組件樹中的多個嵌套異步依賴解決時,渲染一個加載狀態。
為了解釋 <Suspense>
嘗試解決的問題以及它如何與這些異步依賴進行互動,讓我們想像一個如下的組件層次結構:
<Suspense>
└─ <Dashboard>
├─ <Profile>
│ └─ <FriendStatus> (具有異步 setup() 的組件)
└─ <Content>
├─ <ActivityFeed> (異步組件)
└─ <Stats> (異步組件)
在這個組件樹中,有多個嵌套組件的渲染依賴於首先解決一些異步資源。沒有 <Suspense>
的情況下,每個組件都需要處理自己的加載/錯誤和已加載狀態。在最糟糕的情況下,我們可能會在頁面上看到三個加載旋轉器,並且內容會在不同的時間顯示出來。
<Suspense>
組件使我們能夠在等待這些嵌套異步依賴解決時,顯示頂層的加載/錯誤狀態。
<Suspense>
可以等待兩種類型的異步依賴:
<script setup>
並帶有頂層 await 表達式的組件。async setup()
Composition API 組件的 setup() 鉤子可以是異步的:
export default {
async setup() {
const res = await fetch(...)
const posts = await res.json()
return {
posts
}
}
}
如果使用 <script setup>
,頂層 await 表達式的存在會自動使組件成為異步依賴:
<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>
<template>
{{ posts }}
</template>
異步組件默認是“可暫停”的。這意味著如果它在父鏈中有 <Suspense>
,它將被視為該 <Suspense>
的異步依賴。在這種情況下,加載狀態將由 <Suspense>
控制,而組件本身的加載、錯誤、延遲和超時選項將被忽略。
異步組件可以通過在其選項中指定 suspensible: false
來選擇不受 <Suspense>
控制,並讓組件始終控制其自己的加載狀態。
<Suspense>
組件有兩個插槽:#default
和 #fallback
。這兩個插槽都只允許一個直接的子節點。如果可能,將顯示默認插槽中的節點。如果不可能,將顯示回退插槽中的節點。
<template>
<Suspense>
<!-- 具有嵌套異步依賴的組件 -->
<Dashboard />
<!-- 通過 #fallback 插槽顯示加載狀態 -->
<template #fallback>
Loading...
</template>
</Suspense>
</template>
在初始渲染時,<Suspense>
會在內存中渲染其默認插槽內容。如果在此過程中遇到任何異步依賴,它將進入等待狀態。在等待狀態期間,將顯示回退內容。當所有遇到的異步依賴解決後,<Suspense>
進入已解決狀態,並顯示已解決的默認插槽內容。
如果在初始渲染期間沒有遇到異步依賴,<Suspense>
將直接進入已解決狀態。
一旦進入已解決狀態,只有在 #default
插槽的根節點被替換時,<Suspense>
才會恢復到等待狀態。嵌套在樹中更深處的新異步依賴不會導致 <Suspense>
恢復到等待狀態。
當發生恢復時,不會立即顯示回退內容。相反,<Suspense>
將顯示之前的 #default
內容,同時等待新內容及其異步依賴被解決。這種行為可以通過 timeout
屬性配置:如果渲染新默認內容花費的時間超過 timeout
,<Suspense>
將切換到回退內容。timeout
值為 0 時,當默認內容被替換時,將立即顯示回退內容。
<Suspense>
組件會觸發三個事件:pending
、resolve
和 fallback
。pending
事件在進入等待狀態時觸發。resolve
事件在默認插槽的新內容解析完成時觸發。fallback
事件在顯示回退插槽內容時觸發。
這些事件可以用來在新組件加載時,在舊的 DOM 前顯示加載指示器。
<Suspense>
目前不通過自身組件提供錯誤處理功能——然而,你可以使用 errorCaptured
選項或 onErrorCaptured()
鉤子在 <Suspense>
的父組件中捕獲並處理異步錯誤。
通常會希望將 <Suspense>
與 <Transition>
和 <KeepAlive>
組件結合使用。這些組件的嵌套順序對於正確運行它們非常重要。
此外,這些組件經常與 Vue Router 的 <RouterView>
組件一起使用。
下面的範例展示了如何嵌套這些組件,以便它們都能按預期運行。對於較簡單的組合,可以移除不需要的組件:
<template>
<RouterView v-slot="{ Component }">
<template v-if="Component">
<Transition mode="out-in">
<KeepAlive>
<Suspense>
<!-- 主內容 -->
<component :is="Component"></component>
<!-- 加載狀態 -->
<template #fallback>
Loading...
</template>
</Suspense>
</KeepAlive>
</Transition>
</template>
</RouterView>
</template>
Vue Router 支援使用動態導入來延遲加載組件。這些與異步組件不同,且目前不會觸發 <Suspense>
。然而,它們仍然可以有異步組件作為後代,並且這些後代可以按照通常方式觸發 <Suspense>
。
僅支援於 3.3+
當我們有多個異步組件(常見於嵌套或基於佈局的路由)時,如下所示:
<template>
<Suspense>
<component :is="DynamicAsyncOuter">
<component :is="DynamicAsyncInner" />
</component>
</Suspense>
</template>
<Suspense> 會如預期地創建一個邊界,解決樹狀結構中的所有異步組件。然而,當我們更改 DynamicAsyncOuter
時,<Suspense> 會正確等待,但當我們更改 DynamicAsyncInner
時,嵌套的 DynamicAsyncInner
會在解析完成之前渲染一個空節點(而不是先前的節點或 fallback
插槽)。
為了解決這個問題,我們可以使用嵌套的 suspense 來處理嵌套組件的補丁,如下所示:
<template>
<Suspense>
<component :is="DynamicAsyncOuter">
<Suspense suspensible> <!-- 這裡 -->
<component :is="DynamicAsyncInner" />
</Suspense>
</component>
</Suspense>
</template>
如果不設置 suspensible
屬性,內部的 <Suspense> 會被父級 <Suspense> 視為同步組件。這意味著它有自己的 fallback
插槽,如果兩個動態組件同時變更,可能會出現空節點和多個補丁週期,而子級 <Suspense> 正在加載其自己的依賴樹,這可能是不理想的。設置 suspensible
屬性後,所有的異步依賴處理將交給父級 <Suspense>(包括觸發的事件),而內部的 <Suspense> 僅作為另一個依賴解析和補丁的邊界。
看完這些文章還是沒有很懂www
應該就是應用在以下情境中
是的,<Suspense>
的主要應用之一是處理加載狀態,但它的用途不僅限於加載器。以下是一些 <Suspense>
可以用於的場景:
<Suspense>
來管理加載狀態,避免顯示未加載的數據。<Suspense>
可以用於處理異步路由組件的加載,這樣在導航到新路由時可以顯示加載指示器。<Suspense>
可以協調它們的加載,確保在所有依賴被解析之前不會顯示任何內容。<Suspense>
本身不提供錯誤處理,但可以與其他錯誤捕獲組件(如 errorCaptured
)結合使用,以便在異步加載過程中捕獲並處理錯誤。<Transition>
組件結合使用時,可以在加載或變更組件時應用過渡效果,增強用戶體驗。<Suspense>
中可以幫助組織代碼,保持組件的簡潔性,讓異步邏輯更具可讀性和可維護性。<Suspense>
提供了一種優雅的方式來處理異步組件的加載和錯誤管理,無論是用於單個組件的加載,還是多個組件的嵌套加載,它都能幫助開發者改善用戶體驗。