Vuejs
Tutorial Vuejs: Introducción a Suspense
Vuejs Introducción a Suspense: Aprende a gestionar componentes y datos asíncronos eficientemente en Vue.js mostrando contenido provisional mientras se resuelven las dependencias.
Aprende Vuejs GRATIS y certifícate¿Qué es Suspense
en Vue.js?
Suspense
es un componente incorporado en Vue.js que permite gestionar componentes asíncronos y la obtención de datos que requieren tiempo para resolverse. Introducido en Vue 3, Suspense
proporciona una manera elegante de mostrar contenido de respaldo (default) mientras se resuelven las dependencias asíncronas, mejorando así la experiencia del usuario.
Cabe destacar que se trata de una feature experimental, por lo que no podemos garantizar que alcance un estado estable y la API puede tener cambios tras ser completamente estable
En aplicaciones modernas, es común que los componentes dependan de operaciones asíncronas como peticiones a APIs o carga dinámica de datos. Sin Suspense
, los desarrolladores debían manejar manualmente los estados de carga y los casos en los que los datos aún no estaban disponibles, lo que complicaba el código y podía generar inconsistencias.
Suspense
simplifica este proceso al permitir que los componentes declaren sus dependencias asíncronas y gestionen automáticamente el renderizado cuando todos los recursos están listos. Mientras tanto, los usuarios ven un contenido de reserva que puede ser un indicador de carga u otro componente provisional.
El funcionamiento de Suspense
se basa en envolver los componentes asíncronos dentro del componente Suspense
. Si los componentes hijos están esperando datos o en proceso de carga, Suspense
muestra el fallback especificado hasta que todo esté preparado. Una vez que las dependencias se resuelven, el contenido principal se renderiza automáticamente.
Con Suspense
, se facilita el manejo de escenarios asíncronos en Vue.js, permitiendo un código más limpio y una mejor experiencia para el usuario final.
Configuración básica de Suspense
Para utilizar Suspense
en una aplicación Vue, es necesario comprender su estructura básica y cómo se integra en el flujo de componentes. El componente Suspense
actúa como un contenedor que envuelve componentes asíncronos, permitiendo gestionar de forma sencilla los estados de carga y renderizado.
La sintaxis fundamental de Suspense
implica utilizar dos slots nombrados: default
y fallback
. El slot default
contiene el contenido principal que eventualmente se renderizará, mientras que el slot fallback
proporciona contenido alternativo que se muestra mientras los componentes hijos están pendientes de resolver sus operaciones asíncronas.
Aquí se presenta un ejemplo básico de cómo implementar Suspense
:
<template>
<Suspense>
<template #default>
<!-- Contenido principal que depende de datos asíncronos -->
<ComponenteAsincrono />
</template>
<template #fallback>
<!-- Contenido que se muestra mientras se cargan los datos -->
<div>Cargando...</div>
</template>
</Suspense>
</template>
En este ejemplo, <ComponenteAsincrono />
representa un componente cuyo contenido requiere una operación asíncrona, como una llamada a una API. Mientras este componente está resolviendo sus datos, el slot fallback
mostrará al usuario un mensaje de carga o un indicador de progreso.
Es importante destacar que Suspense
se encarga automáticamente de determinar cuándo todos los componentes asíncronos dentro del slot default
han completado sus operaciones. Una vez que esto ocurre, el contenido del slot default
se renderiza, reemplazando al contenido del slot fallback
.
Para que Suspense
funcione correctamente, los componentes hijos deben manejar sus operaciones asíncronas mediante el uso de la API de composición de Vue, específicamente utilizando async
. Un componente asíncrono básico podría definirse de la siguiente manera:
<script setup lang="ts">
import { ref } from 'vue'
const datos = ref(null)
async function obtenerDatos() {
// Simulación de una llamada a una API
datos.value = await fetchDatosDesdeAPI()
}
await obtenerDatos()
</script>
<template>
<div>
<!-- Renderizado del contenido una vez que los datos están disponibles -->
<p>Datos: {{ datos }}</p>
</div>
</template>
En este componente, la función obtenerDatos()
es declarada como async
, lo que permite utilizar await
para esperar la resolución de las operaciones asíncronas. De esta forma, Suspense
puede detectar que el componente está en un estado pendiente y manejar adecuadamente la transición entre los slots fallback
y default
.
Al configurar Suspense
, es recomendable proporcionar una experiencia de usuario fluida al diseñar contenido de reserva que informe claramente al usuario que se está cargando información. Esto puede incluir animaciones, barras de progreso o mensajes personalizados que mejoren la interacción.
De esta manera, Suspense
se convierte en una herramienta eficaz para manejar operaciones asíncronas en Vue, simplificando el código y mejorando la experiencia del usuario.
Uso de Suspense
con componentes asíncronos
El uso de componentes asíncronos es una técnica eficiente para mejorar el rendimiento de una aplicación Vue, permitiendo cargar componentes sólo cuando son necesarios. Al combinar componentes asíncronos con Suspense
, se puede gestionar de forma elegante la carga y presentación de estos componentes, mejorando la experiencia del usuario.
Para definir un componente asíncrono en Vue, se utiliza una función que devuelve una promesa que resuelve el componente. Por ejemplo:
<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
const ComponenteAsincrono = defineAsyncComponent(() =>
import('./ComponenteAsincrono.vue')
)
</script>
<template>
<Suspense>
<template #default>
<ComponenteAsincrono />
</template>
<template #fallback>
<div>Cargando componente...</div>
</template>
</Suspense>
</template>
En este ejemplo, ComponenteAsincrono
se carga de forma dinámica cuando es necesario. El componente Suspense
envuelve al componente asíncrono y muestra el contenido del slot fallback
mientras el componente se carga.
Es posible personalizar aún más el componente asíncrono utilizando opciones adicionales. Por ejemplo, se puede implementar un tiempo de espera o un componente de error en caso de que la carga falle:
<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
const ComponenteAsincrono = defineAsyncComponent({
loader: () => import('./ComponenteAsincrono.vue'),
loadingComponent: {
template: '<div>Cargando...</div>'
},
errorComponent: {
template: '<div>Error al cargar el componente.</div>'
},
delay: 2000,
timeout: 3000,
})
</script>
<template>
<Suspense>
<template #default>
<ComponenteAsincrono />
</template>
<template #fallback>
<div>Cargando componente asíncrono...</div>
</template>
</Suspense>
</template>
En este caso, se utilizan las propiedades loadingComponent
y errorComponent
para especificar componentes que se mostrarán durante la carga o si ocurre un error. Las propiedades delay
y timeout
controlan el comportamiento del loader, estableciendo un retraso antes de mostrar el componente de carga y un tiempo máximo antes de considerar que ha ocurrido un error.
El uso de Suspense
con componentes asíncronos facilita el manejo de varios componentes que pueden tardar en cargarse. Por ejemplo, si se tienen múltiples componentes asíncronos, Suspense
esperará a que todos se hayan resuelto antes de renderizar el contenido:
<template>
<Suspense>
<template #default>
<ComponenteUno />
<ComponenteDos />
</template>
<template #fallback>
<div>Cargando contenido...</div>
</template>
</Suspense>
</template>
Aquí, ComponenteUno
y ComponenteDos
podrían ser componentes asíncronos o dependientes de datos que requieren tiempo para obtenerse. El fallback proporciona una retroalimentación al usuario mientras espera.
Además, es posible anidar varios componentes Suspense
para manejar diferentes niveles de carga. Esto permite mostrar diferentes indicadores de carga para distintas partes de la interfaz de usuario:
<template>
<Suspense>
<template #default>
<SeccionPrincipal />
<Suspense>
<template #default>
<SeccionSecundaria />
</template>
<template #fallback>
<div>Cargando sección secundaria...</div>
</template>
</Suspense>
</template>
<template #fallback>
<div>Cargando sección principal...</div>
</template>
</Suspense>
</template>
En este ejemplo, se proporciona una experiencia más detallada al usuario, mostrando mensajes de carga específicos para cada sección.
Es importante tener en cuenta que los componentes asíncronos y Suspense
trabajan de la mano para optimizar la carga y renderización de la aplicación. Mientras que los componentes asíncronos permiten dividir el código y cargar sólo lo necesario, Suspense
gestiona de forma eficiente los estados de carga y los presenta de manera coherente al usuario.
Al utilizar Suspense
con componentes asíncronos, se mejora la eficiencia y se ofrece una mejor experiencia al usuario, al tiempo que se mantiene un código limpio y mantenible.
Integración de Suspense
con fetching de datos
El componente Suspense
no sólo es útil para manejar componentes asíncronos, sino que también es una herramienta efectiva para gestionar la obtención de datos desde APIs o fuentes externas. Al integrar Suspense
con peticiones de datos, podemos proporcionar una experiencia de usuario fluida mientras esperamos la respuesta de las operaciones asíncronas.
Para utilizar Suspense
con datos asíncronos, es necesario que los componentes hijos utilicen una función setup
asíncrona o retornen una promesa que Suspense
pueda detectar. Esto permite que Suspense
sepa cuándo el componente está listo para ser renderizado.
A continuación, se presenta un ejemplo de cómo combinar Suspense
con fetching de datos:
<template>
<Suspense>
<template #default>
<DatosUsuario />
</template>
<template #fallback>
<div>Cargando datos del usuario...</div>
</template>
</Suspense>
</template>
<script setup lang="ts">
// No es necesario código adicional aquí; la lógica está en el componente hijo
</script>
En este ejemplo, <DatosUsuario />
es un componente que obtiene información de un usuario desde una API. Mientras los datos están siendo recuperados, se muestra el fallback que indica al usuario que la información está cargándose.
El componente <DatosUsuario />
podría implementarse de la siguiente manera:
<template>
<div>
<h1>{{ usuario.nombre }}</h1>
<p>Correo electrónico: {{ usuario.email }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
interface Usuario {
nombre: string
email: string
}
const usuario = ref<Usuario | null>(null)
async function obtenerDatosUsuario() {
const respuesta = await fetch('https://api.ejemplo.com/usuario/1')
usuario.value = await respuesta.json()
}
await obtenerDatosUsuario()
</script>
En este componente, la función setup
es asíncrona y utiliza await
para obtener los datos del usuario antes de continuar con el renderizado. De esta forma, Suspense
detecta que el componente está en estado de suspensión hasta que la promesa se resuelve.
Es importante destacar que al utilizar await
en setup
, debemos asegurarnos de que el código de obtención de datos esté dentro de una función asíncrona. Esto garantiza que el componente espere a que los datos estén listos antes de renderizarse.
Si se desean manejar errores durante la obtención de datos, se puede emplear un bloque try...catch
:
<script setup lang="ts">
import { ref } from 'vue'
interface Usuario {
nombre: string
email: string
}
const usuario = ref<Usuario | null>(null)
const error = ref<Error | null>(null)
async function obtenerDatosUsuario() {
try {
const respuesta = await fetch('https://api.ejemplo.com/usuario/1')
if (!respuesta.ok) {
throw new Error('Error al obtener los datos del usuario')
}
usuario.value = await respuesta.json()
} catch (e) {
error.value = e as Error
}
}
await obtenerDatosUsuario()
</script>
<template>
<div v-if="error">
<p>Error: {{ error.message }}</p>
</div>
<div v-else>
<h1>{{ usuario.nombre }}</h1>
<p>Correo electrónico: {{ usuario.email }}</p>
</div>
</template>
En este caso, si ocurre un error durante la petición, se almacena en la variable error
y podemos mostrar un mensaje al usuario indicando lo sucedido.
Al combinar Suspense
con obtención de datos asíncrona, es posible mejorar el manejo de estados de carga y errores en la aplicación. El componente Suspense
espera a que todas las promesas dentro de sus componentes hijos se resuelvan antes de renderizar el contenido, mostrando el fallback mientras tanto.
Además, si se necesita utilizar múltiples fuentes de datos o realizar varias peticiones simultáneamente, Suspense
gestionará todas las promesas de forma conjunta:
<template>
<Suspense>
<template #default>
<div>
<DatosUsuario />
<ListaProductos />
</div>
</template>
<template #fallback>
<div>Cargando información...</div>
</template>
</Suspense>
</template>
En este ejemplo, tanto <DatosUsuario />
como <ListaProductos />
realizan peticiones asíncronas. Suspense
mostrará el contenido del fallback hasta que ambas peticiones se resuelvan, proporcionando una interfaz coherente al usuario.
Es esencial recordar que para que Suspense
funcione correctamente con la obtención de datos, las operaciones asíncronas deben estar dentro de un setup
asíncrono o retornar promesas que Suspense
pueda detectar. De esta manera, se aprovecha al máximo esta funcionalidad para mejorar el rendimiento y la usabilidad de la aplicación.
Al utilizar Suspense
de esta forma, se facilita el manejo de estados de carga y errores, y se proporciona una experiencia más sólida al usuario. Integrar Suspense
con fetching de datos es una práctica recomendada para mantener el código limpio y mejorar la eficiencia de nuestras aplicaciones Vue.
Combinación de Suspense
con otros composables
El uso de Suspense
no se limita únicamente a componentes asíncronos o a la obtención de datos; también puede integrarse eficazmente con otros composables personalizados en Vue. Los composables son funciones reutilizables que encapsulan lógica reactiva y pueden incluir operaciones asíncronas. Al combinar Suspense
con composables, podemos gestionar estados de carga y errores de manera más coherente en nuestra aplicación.
Cuando se utilizan composables que realizan operaciones asíncronas, es importante que el componente que los consume pueda esperar a que dichas operaciones se completen antes de renderizarse. Para lograr esto, se puede hacer que el setup
del componente sea una función asíncrona utilizando async
, y luego utilizar await
en los composables asíncronos. De esta manera, Suspense
detectará que el componente está en un estado pendiente y mostrará el contenido de reserva definido en el fallback
.
Por ejemplo, consideremos un composable useDatos
que obtiene datos de una API:
// useDatos.ts
import { ref } from 'vue'
export async function useDatos() {
const datos = ref(null)
async function fetchDatos() {
const respuesta = await fetch('https://api.ejemplo.com/datos')
datos.value = await respuesta.json()
}
await fetchDatos()
return {
datos
}
}
Este composable encapsula la lógica para obtener datos y devuelve una referencia reactiva datos
. Ahora, en nuestro componente, podemos utilizar este composable dentro de un setup
asíncrono:
<script setup lang="ts">
import { useDatos } from './useDatos'
const { datos } = await useDatos()
</script>
<template>
<div>
<p>Datos: {{ datos }}</p>
</div>
</template>
Al utilizar await useDatos()
, nos aseguramos de que el componente espere a que el composable complete su operación asíncrona antes de continuar. Cuando este componente se envuelve dentro de un Suspense
, podemos gestionar el estado de carga de manera efectiva:
<template>
<Suspense>
<template #default>
<ComponenteConDatos />
</template>
<template #fallback>
<div>Cargando datos...</div>
</template>
</Suspense>
</template>
Es importante destacar que los composables pueden manejar no solo la carga de datos, sino también gestión de errores y otras operaciones asíncronas. Al centralizar esta lógica en composables, hacemos que nuestro código sea más modular y mantenible.
Otro ejemplo es un composable que escucha eventos WebSocket:
// useWebSocket.ts
import { ref } from 'vue'
export function useWebSocket(url: string) {
const mensaje = ref(null)
const conectado = ref(false)
const socket = new WebSocket(url)
const conectadoPromise = new Promise<void>((resolve, reject) => {
socket.onopen = () => {
conectado.value = true
resolve()
}
socket.onerror = (err) => {
conectado.value = false
reject(err)
}
})
socket.onmessage = (event) => {
mensaje.value = event.data
}
return {
mensaje,
conectado,
conectadoPromise
}
}
En este caso, el composable useWebSocket
establece una conexión WebSocket y expone referencias reactivas. Si necesitamos esperar a que la conexión se establezca antes de renderizar el componente, podemos utilizar Suspense
junto con una promesa que se resuelva cuando conectado
sea true
:
<script setup lang="ts">
import { useWebSocket } from './useWebSocket'
const { mensaje, conectado, conectadoPromise } = useWebSocket('wss://ejemplo.com/socket')
await conectadoPromise
</script>
<template>
<div>
<p>Conectado: {{ conectado }}</p>
<p>Mensaje: {{ mensaje }}</p>
</div>
</template>
Al utilizar await conectadoPromise
, el componente esperará a que la conexión se establezca antes de continuar. De nuevo, al envolver este componente en un Suspense
, podemos mostrar un indicador de carga mientras la conexión se establece:
<template>
<Suspense>
<template #default>
<ComponenteWebSocket />
</template>
<template #fallback>
<div>Estableciendo conexión...</div>
</template>
</Suspense>
</template>
La combinación de Suspense
con composables asíncronos nos permite manejar de forma elegante situaciones donde múltiples operaciones asíncronas necesitan completarse antes de que el componente pueda renderizarse correctamente. Esto es especialmente útil en aplicaciones complejas donde la sincronización de datos es crítica.
Cabe mencionar que también es posible manejar varios composables asíncronos en un solo componente. En tal caso, se pueden utilizar Promise.all
para esperar a que todas las promesas se resuelvan:
<script setup lang="ts">
import { useDatos } from './useDatos'
import { usePermisos } from './usePermisos'
const [{ datos }, { permisos }] = await Promise.all([useDatos(), usePermisos()])
</script>
<template>
<div>
<p>Datos: {{ datos }}</p>
<p>Permisos: {{ permisos }}</p>
</div>
</template>
De esta manera, el componente espera a que tanto useDatos
como usePermisos
completen sus operaciones asíncronas antes de renderizarse. El Suspense
que envuelve al componente gestionará el estado de carga de forma automática.
Además, al estructurar nuestras operaciones asíncronas dentro de composables y utilizar async setup
en los componentes, aprovechamos al máximo las capacidades de Suspense
para mejorar la experiencia del usuario. Esta combinación permite un código más limpio y mantiene una arquitectura coherente en la aplicación.
Ejercicios de esta lección Introducción a Suspense
Evalúa tus conocimientos de esta lección Introducción a Suspense con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Solicitud HTTP con Axios
Estilización de componentes en Vue.js
Comunicación de componentes con props
Uso de hooks de ciclo de vida en Vue
Introducción a los componentes
Introducción a Vue
Navegación programática y redirección
Uso de la directiva v-if en Vuejs
Crear componente Composition API
Realizar una solicitud GET con Fetch API en Vue
Uso avanzado de los composables
Galería de imágenes con navegación y rutas
Uso de rutas anidadas y dinámicas
Definición y manejo de rutas en Vue
Uso de la directiva v-for en Vuejs
Manejo de eventos con v-on
Crear un componente con Options API en Vue
Creación de rutas con Vue Router
Uso básico de los composables
Binding bidireccional con v-model y defineModel
Instalación y configuración
Lista de tareas básica en Vuejs
Uso de provide e inject
Gestión de tareas con estado global y API
Introducción a la sintaxis de plantillas
Implementar reactividad con ref y reactive
Componente Vue con Suspense
Evaluación test de conocimientos Vuejs
Todas las lecciones de Vuejs
Accede a todas las lecciones de Vuejs y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Vue Y Su Ecosistema
Introducción Y Entorno
Instalar Y Configurar Vue Con Vite
Introducción Y Entorno
Introducción A La Sintaxis De Plantillas
Componentes
Introducción A Componentes
Componentes
Componentes Con Options Api
Componentes
Componentes Con Composition Api
Componentes
Renderizado Condicional Con V-if
Componentes
Renderizado Iterativo Con V-for
Componentes
Props Y Comunicación Entre Componentes
Componentes
Manejo De Eventos En Vue Con V-on
Componentes
Binding Bidireccional Con V-model Y Definemodel
Componentes
Estilización De Componentes
Componentes
Reactividad Con Ref Y Reactive
Composición Y Reactividad
Ciclo De Vida Con Composition Api
Composición Y Reactividad
Composition Api: Provide E Inject
Composición Y Reactividad
Introducción A Los Composables
Composición Y Reactividad
Uso Avanzado De Composables
Composición Y Reactividad
Introducción A Vue Router
Navegación Y Enrutamiento
Definición Y Manejo De Rutas
Navegación Y Enrutamiento
Rutas Anidadas Y Dinámicas
Navegación Y Enrutamiento
Navegación Programática Y Redirección
Navegación Y Enrutamiento
Solicitudes Http Con Fetch Api
Interacción Http Con Apis De Backend
Solicitudes Http Con Axios
Interacción Http Con Apis De Backend
Introducción A Suspense
Interacción Http Con Apis De Backend
Evaluación Test De Conocimientos Vuejs
Evaluación
Certificados de superación de Vuejs
Supera todos los ejercicios de programación del curso de Vuejs y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender el concepto y los usos de
Suspense
en Vue.js. - Implementar
Suspense
para gestionar componentes y datos asíncronos. - Configurar
Suspense
condefault
yfallback
slots. - Manejar errores y estados de carga en componentes asíncronos.
- Integrar
Suspense
con composables y otras funciones reactivas.