Suspense

  • handle asynchronous components and improve user experience during loading.

Key concept

  • Async Components:

Suspense simplifies the handling of components that require asynchronous data or code loading.

  • Fallback Content:

You can define fallback content to be displayed while the asynchronous component is loading.

2 types of async dependencies that can wait on:

  • Components with an async setup() hook. This includes components using with top-level await expressions.

<script>
export default {
  async setup() {
    const res = await fetch(...)
    const posts = await res.json()
    return {
      posts
    }
  }
}
</script>
  • Async components

    • suspensible by default: meaning that loading state will be automatically controlled by the "Suspense" component.

    • to opt-opt the suspense controlled, one can define "suspensible: false"

Slots:

  • The component has two slots: #default for regular content and #fallback for loading state content.

  • Only one immediate child node is allowed in each slot.

  • The content in the #default slot is displayed if possible; otherwise, the content in the #fallback slot is shown.

  • example:

<Suspense>
  <!-- Component with nested async dependencies -->
  <Dashboard />

  <!-- Loading state via #fallback slot -->
  <template #fallback>
    Loading...
  </template>
</Suspense>
  • Lifecycle:

    • On initial render, 'Suspense' renders its default slot content in memory.

    • If async dependencies are encountered, it enters a pending state, displaying the fallback content.

    • When all async dependencies are resolved, 'Suspense' enters a resolved state, showing the resolved default slot content.

    • If no async dependencies were encountered during initial render, 'Suspense' directly goes into a resolved state.

  • Reverting to Pending State:

    • 'Suspense' reverts to a pending state only if the root node of the #default slot is replaced.

    • New async dependencies deeper in the tree won't trigger a revert to a pending state.

  • Revert Behavior:

    • When a revert happens, fallback content is not immediately displayed.

    • 'Suspense' shows the previous #default content while waiting for the new content and its async dependencies to be resolved.

    • The timeout prop can be used to configure the revert behavior. If rendering the new content takes longer than the specified timeout, 'Suspense' switches to fallback content.

    • A timeout value of 0 displays the fallback content immediately when default content is replaced.

Suspense events

  1. Pending Event:

  • Event Name: pending

  • Description: Occurs when the component enters a pending state. This typically happens when there are asynchronous dependencies being resolved.

  • Usage: display a loading indicator

  1. Resolve Event:

  • Event Name: resolve

  • Description: Emitted when new content in the default slot has finished resolving. This event signifies that the asynchronous dependencies have been successfully resolved.

  • Usage: handle the successful resolution of asynchronous dependencies

  1. Fallback Event:

  • Event Name: fallback

  • Description: Fired when the contents of the fallback slot are shown. This event is triggered when the component enters a pending state, and the fallback content is displayed.

  • Usage: perform actions when fallback content is shown

Error handling

  • 'Suspense' itself does not provide built-in error handling for asynchronous operations.

  • use 'errorCaptured' or 'onErrorCaptured()' hook for error handling

Combining with other components

  • the nesting order of components is important !!!!

Components Combination Example

Components Used:

  • 'RouterView': Vue Router's component for displaying matched components.

  • 'Transition': Vue's transition component for handling transitions between components.

  • 'KeepAlive': Vue's component for caching and keeping alive components.

  • 'Suspense': Vue's component for handling loading states during asynchronous

<RouterView v-slot="{ Component }">
  <template v-if="Component">
    <Transition mode="out-in">
      <KeepAlive>
        <Suspense>
          <!-- Main Content -->
          <component :is="Component"></component>

          <!-- Loading State -->
          <template #fallback>
            Loading...
          </template>
        </Suspense>
      </KeepAlive>
    </Transition>
  </template>
</RouterView>

Nesting Order:

  • 'RouterView' is used to display the matched component.

  • Inside 'RouterView', there is a check for the existence of the component ('template v-if="Component"') before applying transitions.

  • 'Transition' is used to manage the transition effect between components (mode="out-in").

  • 'KeepAlive' is employed to cache and keep alive components, preserving their state.

  • 'Suspense' wraps the main content and provides a loading state using the #fallback slot.

Last updated