React 19 de Cero a Experto / Datos
Suspense y Error Boundaries: carga a nivel de árbol
Hasta ahora, cada componente comprobaba su propio isLoading y su propio isError. Hay otra forma,
más declarativa: dejar que React coordine la carga y los errores a nivel de ÁRBOL. <Suspense> se
encarga del "cargando" de todo lo que envuelve, y un ERROR BOUNDARY atrapa los errores de sus hijos
sin que la app entera se caiga. Hoy entiendes ese modelo —y ves un Error Boundary funcionando en
vivo—.
El telón y la red de seguridad
Suspense: el estado de carga, declarativo
Con <Suspense>, en vez de que cada componente revise isLoading, ENVUELVES la parte que carga y
das un fallback. Mientras algún hijo esté "suspendido" (esperando datos), React muestra el
fallback:
import { Suspense } from "react";
import { useSuspenseQuery } from "@tanstack/react-query";
function Gastos() {
// useSuspenseQuery: 'data' está SIEMPRE lista aquí (si no, el componente se suspende).
// Sin isLoading ni isError: de eso se encargan Suspense y el Error Boundary de afuera.
const { data } = useSuspenseQuery({ queryKey: ["gastos"], queryFn: obtenerGastos });
return <ul>{data.map((g) => <li key={g.id}>{g.nombre}</li>)}</ul>;
}
function Pagina() {
return (
<Suspense fallback={<p>Cargando gastos…</p>}>
<Gastos /> {/* mientras carga, se ve el fallback; sin ifs de isLoading */}
</Suspense>
);
}Fíjate: dentro de Gastos, data SIEMPRE existe —no hay if (isLoading)—. Si los datos no están
listos, el componente se "suspende" y <Suspense> muestra el fallback por él. El estado de carga
sube al árbol: un solo <Suspense> puede cubrir varios componentes que cargan, con un único
"Cargando…". Es la misma idea del use() del módulo 4, aquí integrada con TanStack Query.
Error Boundary: la red de seguridad (en vivo)
Un Error Boundary es un componente que atrapa los errores que sus hijos lanzan AL RENDERIZAR, y muestra una UI de repuesto en vez de dejar que la app entera se caiga. Este playground tiene uno funcionando —rompe el componente y observa que la app sobrevive—:
Pulsa "Romper el componente": Riesgoso lanza un error al renderizar, el ErrorBoundary lo atrapa
(vía getDerivedStateFromError) y muestra su fallback —el resto de la app sigue intacta—. "Reintentar"
limpia el error y vuelve a montar el hijo. Sin el boundary, ese error tumbaría toda la interfaz
(pantalla blanca). Es la "red de seguridad" que aísla los fallos a una sección.
¿Qué hacen Suspense y un Error Boundary, y qué tipo de errores NO atrapa el boundary?
Mini-reto
Amplía el playground: 1) haz que Riesgoso reciba una prop nombre y lance un error con ese nombre
en el mensaje; 2) pon DOS <Riesgoso> cada uno en su propio <ErrorBoundary>, y comprueba que romper
uno no afecta al otro (aislamiento); 3) agrega un tercer componente FUERA de los boundaries que
muestre la hora, y verifica que sigue vivo cuando rompes los otros. Observa cómo el boundary limita el
daño a su subárbol.
Qué sigue
Cierras el módulo construyendo TU PROPIO useQuery en miniatura —un hook con caché y estados que
CORRE en vivo—, para entender por dentro la máquina que es TanStack Query. Es el mismo enfoque "desde
cero" con el que en JavaScript hiciste tu propio expect y tu propio pub-sub: primero la entiendes,
luego usas la industrial con criterio.