Vue Suspense - A Cleaner Way to Manage Loading States

Vue Suspense - A Cleaner Way to Manage Loading States

One exciting feature of Vue 3 is Suspense. It is a built-in component that makes loading state orchestration much simpler.

⚠️ Disclaimer: Suspense is an experimental feature and the API might change before reaching the stable release.

To demonstrate the problem, imagine a nested hierarchy of multiple components that are either lazy-loaded or require data fetching from a remote service. Each component has to handle its own loading state, and the UI jumps around, causing layout shifts which negatively affect your core web vitals.

The problem is evident from the video below.

Source code of the above experiment without suspense

Multiple loading states and layout shifts result in a frustrating user experience.

The suspense element has two slots named #default and #fallback and both of them have one immediate child node. While the default slot is loading, the fallback is displayed.

<Suspense>
  <!-- component with nested async dependencies -->
  <Links />

  <!-- loading state via #fallback slot -->
  <template #fallback>
    <Loader />
  </template>
</Suspense>

Suspense, will automatically detect any async components or async setup hooks and will wait for both of them to be fulfilled until the default slot is displayed.

For our example, we need to wrap all the sections to the Suspense element and move the loader logic from each component to the fallback section.

<template>
  <HelloWorld msg="Hello Vue 3!" />
  <Suspense>
    <div>
      <TheEcosystem />
      <ThePlugins />
      <TheLinks />
    </div>
    <template #fallback>
      <loadingComponent />
    </template>
  </Suspense>
</template>

You can tell the difference from the video below.

Source code of the above experiment with suspense

We eliminated multiple UI layout shifts, and the code is now much cleaner after removing multiple loading states. Nice work! 👏👏👏