Vue3新特性系列:Suspense组件

834 阅读2分钟

「这是我参与2022首次更文挑战的第39天,活动详情查看:2022首次更文挑战」。

我在写关于Vue3新特性系列的文章,今天的主要讲讲在Vue3中新特性中,非常有趣的Suspense组件。

什么是Suspense?

在React当中,Suspense 是一个特殊的组件,它在满足条件之前呈现指定内容而不是组件。这种情况通常是在您的组件功能中发生的异步操作,比如在用户等待时显示的一些特定的内容。在vue3中,终于也加入了类似的功能。

通常,在组件上渲染加载动画可以使用简单的 v-ifv-else 来实现,示例如下:

<div v-if="loading">
    # loading animation
</div>
<div v-else>
    ...
</div>

使用 <suspense>,我们可以按照如下代码重写相同的功能。

<Suspense>
    <template #default>
        ...
    </template>
    <template #fallback>
        # loading animation
    </template>
</Suspense>

注意,<suspense> 组件提供了两个插槽,#default#fallback#default 中的任何节点只有在其所有异步操作完成后才会呈现。否则,组件将呈现#fallback

基本用法

下面的代码片段显示了一个简单的示例,说明在等待 API数据时使用<suspense> 呈现加载动画。

# User.vue
<template>
    {{ data }}
</template>

<script setup>
import { ref } from 'vue'
import { fetchData } from './utils'

const data = ref(null)
data.value = await fetchData()
</script>
# Home.vue
<template>
    <Suspense>
        <template #default>
            <User/>
        </template>
        <template #fallback>
            Loading...
        </template>
    </Suspense>
</template>

<script setup>
import User from './User.vue'
</script>

在上面的例子中,Loading... 文本被渲染,直到 fetchData()User.vue 中完成。需要注意的是,如果 <User/> 组件抛出任何错误,是缺少错误处理的。

在下面示例中,创建了一个 <SuspenseWithErrorHandling> 新组件来扩展 <suspense> 的使用并支持基本的错误处理。

# SuspenseWithErrorHandling.vue
<template>
    <slot name="error" v-if="$slots?.error" />
    <Suspense v-else>
        <template #default>
            <slot name="default" />
        </template>
        <template #fallback>
            <slot name="fallback" />
        </template>
    </Suspense>
</template>
# Home.vue
<template>
    <SuspenseWithErrorHandler>
        <template #error v-if="error">
            {{ error }}
        </template>
        <template #default>
            <User/>
        </template>
        <template #fallback>
            Loading...
        </template>
    </SuspenseWithErrorHandler>
</template>

<script setup>
import { ref, onErrorCaptured } from 'vue'
import User from './User.vue'
import SuspenseWithErrorHandling from './SuspenseWithErrorHandling.vue'

const error = ref(null)
onErrorCaptured(err => { 
    error.value = err
})
</script>

上述代码使用 onErrorCaptured 钩子来检测 <User/> 组件引发的错误。然后,使用新创建的 <SuspenseWithErrorHandler/> 显示此错误。这样,每当组件失败时,它就不会渲染#fallback,而是显示#error slot 中提供的元素。

总结

Suspense 是一个非常方便的组件,它能够以一种简单而优雅的方式显示备选内容,直到执行异步操作。使用 ErrorCaptured 生命周期钩子,还可以优雅地处理挂起组件中发生的错误。