It has been roughly a year since VueJs had its major upgrade in 2020 and it has grown more attention since. Not only did Vue3 was a major rewrite from the earlier version Vue2, but it also came with many new and enjoyable features to make development more convenient.
Before we proceed, allow me to introduce myself. I am Adean, a back-end developer from AnyTag team and in this article, I’ll be introducing one new and still experimental feature of Vue3 called <suspense>
.
A little disclaimer:
- At the time of writing,
<suspense>
is still an experimental feature and is not production ready. - This article assumes that you have basic familiarity with Vue3.
Now let’s stop with all this suspense and let’s talk about <suspense>
.
Vue3 and its Suspense component
Vue is an open source javascript UI framework and is arguably one of the most popular frameworks in the market for 2021. In September 2020, Vue3 was officially released with the aim to be the faster, smaller, and overall better UI framework compared to its predecessors. It came with a major rewrite from the old version (Vue2) while preserving most if not all of its APIs.
One of it’s new features is <suspense>
, a special component that allows you to render fallback contents until a specific condition is fulfilled. These conditions can be async operations executed inside the component. A common usecase for <suspense>
is to show a loading indicator while waiting for data fetched from an external API.
Suspense slots
Normally, rendering a loading animation on your component can be implemented with a simple v-if
and v-else
as shown in the snippet below.
<div v-if="loading">
# loading animation
</div>
<div v-else>
...
</div>
With <suspense>
, we can rewrite the same code in the manner shown below.
<Suspense>
<template #default>
...
</template>
<template #fallback>
# loading animation
</template>
</Suspense>
Notice that the <suspense>
component provides two slots namely #default
and #fallback
. Any nodes within the #default
slot will be rendered only if all its async operations are completed. Otherwise, the component will render the #fallback
.
Basic usage
The snippet below shows a simple example of how to use <suspense>
to render loading animation while waiting for the data from the API.
# Home.vue
<template>
<Suspense>
<template #default>
<User/>
</template>
<template #fallback>
Loading...
</template>
</Suspense>
</template>
<script setup>
import User from './User.vue'
</script>
And, here’s our simple <User/>
component
# User.vue
<template>
{{ data }}
</template>
<script setup>
import { ref } from 'vue'
import { fetchData } from './utils'
const data = ref(null)
data.value = await fetchData()
</script>
From the example above, the Loading...
text will be rendered until the fetchData()
is completed in User.vue
. However, we have one noticeable problem here and that is the absence of error handling if <User/>
component throws any errors.
In our next example, we will create a new component called <SuspenseWithErrorHandling>
to extend the use of <suspense>
and support basic error handling.
# 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>
Notice that we used onErrorCaptured
hook to detect errors raised from the <User/>
component. Then, we show this error using the newly created <SuspenseWithErrorHandler/>
. With this, whenever the component fails, it will not render our #fallback
, instead, it will show the element provided in #error
slot.
Let’s wrap things up!
Overall, I think <suspense>
is a neat solution to showing a fallback display for your components. It provides very straightforward methods to manage default and fallback contents.
If you wish to read more about <suspense>
, check out the official Vue3 documentation here.
I hope you find this article helpful and maybe in the future you will consider using <suspense>
too.
Thank you.