Vanta Logo
SPONSOR
Automate SOC 2 & ISO 27001 compliance with Vanta. Get $1,000 off.
Published
4 min read
Up to date

Trevor I. Lasn

Staff Software Engineer, Engineering Manager

Understanding Vue's Suspense

How the Suspense component manages async dependencies and improves loading states in Vue apps

The <Suspense> component is an experimental feature in Vue. It’s designed to help manage async dependencies in your component tree.

While it’s still experimental and might change, it offers a powerful way to handle loading states when dealing with async components.

What Problem Does Suspense Solve?

When working with components that depend on async data, you often need to manage loading states manually.

Imagine you have a dashboard component with several nested components, each relying on data fetched asynchronously.

Without <Suspense>, each of these components would need its own loading logic, which could result in multiple spinners or loading indicators popping up at different times. This can create a jarring user experience.

With <Suspense>, you can manage the loading state at a higher level. Instead of each component handling its own loading state, <Suspense> allows you to display a single loading state while waiting for all async dependencies in the component tree to resolve.

How Does <Suspense> Work?

The <Suspense> component works by wrapping other components. It has two slots: #default and #fallback.

<Suspense>
<!-- Component with async dependencies -->
<UserProfile />
<!-- Loading state via #fallback slot -->
<template #fallback>
<div class="spinner">Loading user profile...</div>
</template>
</Suspense>

The #default slot contains the component or content that should be displayed once everything is ready.

The #fallback slot is where you define what should be shown while waiting for the async operations to complete.

When the component renders, Vue tries to render the content in the #default slot. If it encounters any async dependencies (like a component using async setup()), it will switch to the #fallback slot until everything is ready.

Understanding Async Dependencies

There are two types of async dependencies that <Suspense> can wait on:

  • Components with async setup() hooks: If a component’s setup function is async, it automatically becomes an async dependency for <Suspense>.
const data = await fetchData();
<template>
<div>{{ data }}</div>
</template>
  • Async Components: These are components that are explicitly defined as async. If they are part of the <Suspense> component tree, their loading states are managed by <Suspense>.
export default {
async setup() {
const data = await fetchData();
return { data };
}
}
<template>
<div>{{ data }}</div>
</template>

Handling Events with <Suspense>

The <Suspense> component emits three key events: pending, resolve, and fallback.

  • pending: Triggered when the component enters a pending state, indicating that async dependencies are being resolved.
<Suspense @pending="handlePending">
<template #default>
<UserProfile />
</template>
<template #fallback>
<div class="spinner">Loading...</div>
</template>
</Suspense>
function handlePending() {
console.log('Loading state started');
}
  • resolve: Emitted once the content in the #default slot has finished loading and is ready to be displayed.
<Suspense @resolve="handleResolve">
<template #default>
<UserProfile />
</template>
<template #fallback>
<div class="spinner">Loading...</div>
</template>
</Suspense>
function handleResolve() {
console.log('Content fully loaded');
}
  • fallback: Fired when the #fallback slot content is shown, typically while waiting for async operations to complete.
<Suspense @fallback="handleFallback">
<template #default>
<UserProfile />
</template>
<template #fallback>
<div class="spinner">Loading...</div>
</template>
</Suspense>
function handleFallback() {
console.log('Showing fallback content');
}

Managing the Loading State

The beauty of <Suspense> is in how it manages loading states. When the component is initially rendered, Vue tries to render the default content. If it encounters async operations, it shows the fallback content. Once all async dependencies resolve, the default content is displayed.

<Suspense>
<!-- Dashboard with async data -->
<UserDashboard />
<!-- Custom loading state -->
<template #fallback>
<div class="loading">Loading dashboard, please wait...</div>
</template>
</Suspense>

This makes it easy to manage complex loading scenarios without the need for multiple loading indicators scattered throughout your component tree.

Handling Errors

While <Suspense> is great for managing loading states, it doesn’t directly handle errors. For error handling, you can use Vue’s errorCaptured option or the onErrorCaptured() hook in the parent component.

Combining <Suspense> with Other Vue Components

You might want to use <Suspense> alongside components like <Transition>, <KeepAlive>, or <RouterView>. The nesting order is important here to ensure everything works as expected.

<RouterView v-slot="{ Component }">
<template v-if="Component">
<Transition mode="out-in">
<KeepAlive>
<Suspense>
<!-- Main settings content -->
<component :is="Component" />
<!-- Loading spinner -->
<template #fallback>
<div class="loading">Loading settings...</div>
</template>
</Suspense>
</KeepAlive>
</Transition>
</template>
</RouterView>

The setup above allows you to combine transitions, caching, and async handling smoothly.

Nested <Suspense>

In more complex applications, you might have nested async components. By using nested <Suspense> components, you can control the loading states of deeply nested components independently.

<Suspense>
<AsyncUserProfile>
<Suspense suspensible>
<AsyncUserDetails />
</Suspense>
</AsyncUserProfile>
</Suspense>

Setting the suspensible prop ensures that the inner <Suspense> integrates with the parent, allowing for more precise control over loading states.s

If you found this article helpful, you might enjoy my free newsletter. I share developer tips and insights to help you grow your skills and career.


More Articles You Might Enjoy

If you enjoyed this article, you might find these related pieces interesting as well. If you like what I have to say, please check out the sponsors who are supporting me. Much appreciated!

Javascript
6 min read

Micro Frontends: The LEGO Approach to Web Development

Explore the concept of micro frontends in web development, understand their benefits, and learn when this architectural approach is most effective for building scalable applications.

Oct 2, 2024
Read article
Javascript
5 min read

Working with JavaScript's Scheduler API

Learn how to prioritize and control task execution in JavaScript using the new Scheduler API for better performance and user experience

Nov 26, 2024
Read article
Leadership
4 min read

Make It Work First Before Optimizing

Users don't care how elegant your code is. They care if it solves their problem.

Sep 27, 2024
Read article
Web performance
8 min read

Speculation Rules API: Boosting Web Performance with Prefetching and Prerendering

How the experimental Speculation Rules API improves web performance by prefetching and prerendering future navigations

Sep 15, 2024
Read article
Tech
10 min read

Amazon's Rise to Tech Titan: A Story of Relentless Innovation

How Jeff Bezos' 'Day 1' philosophy turned an online bookstore into a global powerhouse

Sep 30, 2024
Read article
Webdev
4 min read

Programming Trends to Watch in 2020 and Beyond

Here are my bets on the programming trends

Jul 19, 2019
Read article
Webdev
2 min read

link rel='modulepreload': Optimize JavaScript Module Loading

The rel='modulepreload' indicates that a module script should be fetched, parsed, and compiled preemptively, and stored for later execution

Dec 4, 2024
Read article
Web performance
5 min read

Speeding Up React Apps with Code Splitting and Lazy Loading

Performance is not a luxury; it's a necessity

Dec 26, 2023
Read article
Webdev
4 min read

Mental Toughness is the Best Quality a Developer Can Have

Mental toughness gets developers through challenges like debugging, picking up new tools, and hitting tight deadlines. It’s about staying calm and pushing through when things get tough.

Sep 12, 2024
Read article

Become a better engineer

Here are engineering resources I've personally vetted and use. They focus on skills you'll actually need to build and scale real projects - the kind of experience that gets you hired or promoted.

Many companies have a fixed annual stipend per engineer (e.g. $2,000) for use towards learning resources. If your company offers this stipend, you can forward them your invoices directly for reimbursement. By using my affiliate links, you support my work and get a discount at the same!


This article was originally published on https://www.trevorlasn.com/blog/understanding-vue-suspense. It was written by a human and polished using grammar tools for clarity.