CodeForge

React 19 de Cero a Experto / Datos

Suspense y Error Boundaries: carga a nivel de árbol

Teoría22 min20 XP

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:

suspense.tsx
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.