2024-10-21|閱讀時間 ‧ 約 0 分鐘

EP44 - 懸掛

Suspense,這也是新觀念~
但應該跟異步有點關係吧?
快來看看吧!
每天看一篇文章~希望能持續下去啊!
大家會想什麼內容呢?快來留言吧

實驗性功能

<Suspense> 是一個實驗性功能。它不保證會達到穩定狀態,並且 API 在達到穩定狀態之前可能會發生變化。

<Suspense> 是一個內建組件,用於在組件樹中協調異步依賴。它可以在等待組件樹中的多個嵌套異步依賴解決時,渲染一個加載狀態。

異步依賴 - Async Dependencies​

為了解釋 <Suspense> 嘗試解決的問題以及它如何與這些異步依賴進行互動,讓我們想像一個如下的組件層次結構:

<Suspense>
└─ <Dashboard>
├─ <Profile>
│ └─ <FriendStatus> (具有異步 setup() 的組件)
└─ <Content>
├─ <ActivityFeed> (異步組件)
└─ <Stats> (異步組件)

在這個組件樹中,有多個嵌套組件的渲染依賴於首先解決一些異步資源。沒有 <Suspense> 的情況下,每個組件都需要處理自己的加載/錯誤和已加載狀態。在最糟糕的情況下,我們可能會在頁面上看到三個加載旋轉器,並且內容會在不同的時間顯示出來。

<Suspense> 組件使我們能夠在等待這些嵌套異步依賴解決時,顯示頂層的加載/錯誤狀態。

<Suspense> 可以等待兩種類型的異步依賴:

  1. 具有異步 setup() 鉤子的組件。這包括使用 <script setup> 並帶有頂層 await 表達式的組件。
  2. 異步組件

異步 setup() - 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>

異步組件 - Async Components

異步組件默認是“可暫停”的。這意味著如果它在父鏈中有 <Suspense>,它將被視為該 <Suspense> 的異步依賴。在這種情況下,加載狀態將由 <Suspense> 控制,而組件本身的加載、錯誤、延遲和超時選項將被忽略。

異步組件可以通過在其選項中指定 suspensible: false 來選擇不受 <Suspense> 控制,並讓組件始終控制其自己的加載狀態。

加載狀態 - Loading State

<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 時,當默認內容被替換時,將立即顯示回退內容。

事件 - Events

<Suspense> 組件會觸發三個事件:pendingresolvefallbackpending 事件在進入等待狀態時觸發。resolve 事件在默認插槽的新內容解析完成時觸發。fallback 事件在顯示回退插槽內容時觸發。

這些事件可以用來在新組件加載時,在舊的 DOM 前顯示加載指示器。

錯誤處理 - Error Handling​

<Suspense> 目前不通過自身組件提供錯誤處理功能——然而,你可以使用 errorCaptured 選項或 onErrorCaptured() 鉤子在 <Suspense> 的父組件中捕獲並處理異步錯誤。

結合其他組件 - Combining with Other Components​

通常會希望將 <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>

嵌套的 Suspense - Nested 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> 可以用於的場景:

  1. 異步數據獲取:
    • 當一個組件需要從 API 獲取數據時,可以使用 <Suspense> 來管理加載狀態,避免顯示未加載的數據。
  2. 異步路由加載:
    • 在使用 Vue Router 時,<Suspense> 可以用於處理異步路由組件的加載,這樣在導航到新路由時可以顯示加載指示器。
  3. 組件樹的異步加載:
    • 當有多個嵌套的組件需要異步加載時,<Suspense> 可以協調它們的加載,確保在所有依賴被解析之前不會顯示任何內容。
  4. 錯誤處理:
    • 雖然 <Suspense> 本身不提供錯誤處理,但可以與其他錯誤捕獲組件(如 errorCaptured)結合使用,以便在異步加載過程中捕獲並處理錯誤。
  5. 視覺效果和過渡:
    • <Transition> 組件結合使用時,可以在加載或變更組件時應用過渡效果,增強用戶體驗。
  6. 整合和組織代碼:
    • 將異步邏輯封裝在 <Suspense> 中可以幫助組織代碼,保持組件的簡潔性,讓異步邏輯更具可讀性和可維護性。

總結

<Suspense> 提供了一種優雅的方式來處理異步組件的加載和錯誤管理,無論是用於單個組件的加載,還是多個組件的嵌套加載,它都能幫助開發者改善用戶體驗。

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.