Skip to content
← Todas las preguntas
⚡ Intermedio

¿Cómo funciona Suspense con componentes asíncronos?

🧩 Componentes🎰 Slots⏳ Suspense🌀 Teleport

<Suspense> es un componente integrado que renderiza contenido de fallback mientras sus hijos asíncronos se resuelven. Funciona con dos tipos de dependencias asíncronas: componentes asíncronos (defineAsyncComponent) y componentes con un async setup().

Uso básico ​

vue
<template>
  <Suspense>
    <!-- Slot por defecto: el contenido asíncrono -->
    <AsyncDashboard />

    <!-- Slot fallback: se muestra mientras carga -->
    <template #fallback>
      <LoadingSkeleton />
    </template>
  </Suspense>
</template>
Open in Vue Playground

Suspense espera a que todas las dependencias asíncronas dentro del slot por defecto se resuelvan antes de cambiar del fallback al contenido real.

Async setup ​

Un componente con async setup() (usando await de nivel superior en <script setup>) es automáticamente una dependencia de Suspense:

vue
<!-- UserProfile.vue -->
<script setup>
const user = await fetchUser() // await de nivel superior
const posts = await fetchPosts(user.id)
</script>

<template>
  <h1>{{ user.name }}</h1>
  <PostList :posts="posts" />
</template>
Open in Vue Playground
vue
<!-- Parent.vue -->
<template>
  <Suspense>
    <UserProfile />
    <template #fallback>Cargando perfil...</template>
  </Suspense>
</template>
Open in Vue Playground

Un único elemento raíz en cada slot ​

Suspense rastrea un único hijo inmediato por slot. Envuelve varios elementos:

vue
<template>
  <Suspense>
    <div>
      <AsyncHeader />
      <AsyncContent />
    </div>

    <template #fallback>
      <div>
        <LoadingSpinner />
        <p>Cargando...</p>
      </div>
    </template>
  </Suspense>
</template>
Open in Vue Playground

Timeout para re-activaciones ​

Cuando Suspense ya está resuelto y comienza nuevo trabajo asíncrono (por ejemplo, al cambiar de vista), el contenido anterior permanece visible hasta que expira un timeout. Configura timeout para controlar cuándo vuelve a aparecer el fallback:

vue
<template>
  <!-- Muestra el fallback tras 200ms si la nueva vista no ha resuelto -->
  <Suspense :timeout="200">
    <component :is="currentView" :key="currentView" />
    <template #fallback>Cargando...</template>
  </Suspense>
</template>
Open in Vue Playground

Eventos de Suspense ​

Controla el estado de carga programáticamente con @pending, @resolve y @fallback:

vue
<script setup>
import { ref } from 'vue'
const isLoading = ref(false)
</script>

<template>
  <ProgressBar v-if="isLoading" />

  <Suspense @pending="isLoading = true" @resolve="isLoading = false">
    <AsyncPage />
    <template #fallback><PageSkeleton /></template>
  </Suspense>
</template>
Open in Vue Playground

Anidamiento con RouterView, Transition y KeepAlive ​

El orden correcto de anidamiento es RouterView, luego Transition, luego KeepAlive y luego Suspense:

vue
<template>
  <RouterView v-slot="{ Component }">
    <Transition mode="out-in">
      <KeepAlive>
        <Suspense>
          <component :is="Component" />
          <template #fallback>Cargando...</template>
        </Suspense>
      </KeepAlive>
    </Transition>
  </RouterView>
</template>
Open in Vue Playground

Suspense sigue siendo experimental ​

Suspense sigue siendo una API experimental. Funciona, pero la API podría cambiar en versiones futuras. En producción, mantén los límites Suspense al mínimo y documenta dónde los usas.

Ver también: ¿Qué son los componentes asíncronos? · ¿Qué son Teleport, Fragments y Suspense? · ¿Cómo funciona el manejo de errores?

Referencias ​

Publicado bajo la licencia MIT.