TechLead

Error Boundaries y Suspense

Manejo de errores, carga diferida y Suspense para obtención de datos en React

Error Boundaries

Los Error Boundaries son componentes de React que capturan errores de JavaScript en cualquier lugar de su árbol de componentes hijos, registran esos errores y muestran una interfaz de respaldo en lugar de que toda la aplicación se caiga. Funcionan como un bloque try/catch, pero para componentes.

Sin error boundaries, un solo error en un componente puede hacer que toda tu aplicación React se caiga con una pantalla en blanco.

⚠️ Limitaciones Importantes

Los error boundaries no capturan errores en:

  • Manejadores de eventos (usa try/catch regular)
  • Código asíncrono (setTimeout, requestAnimationFrame)
  • Renderizado del lado del servidor
  • Errores lanzados en el propio error boundary

Creando un Error Boundary (Componente de Clase)

Los error boundaries deben ser componentes de clase — los componentes funcionales no pueden capturar errores de renderizado (aún):

import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    console.error('Error capturado:', error);
    console.error('Stack del componente:', errorInfo.componentStack);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="p-6 bg-red-50 border border-red-200 rounded-lg">
          <h2 className="text-red-800 font-bold mb-2">Algo salio mal</h2>
          <p className="text-red-600 mb-4">{this.state.error?.message}</p>
          <button
            onClick={() => this.setState({ hasError: false, error: null })}
            className="px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700"
          >
            Intentar de nuevo
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

React.lazy y Division de Codigo

React.lazy() permite cargar componentes bajo demanda. En lugar de empaquetar todo por adelantado, divides tu código en fragmentos más pequeños que se cargan solo cuando son necesarios.

import React, { lazy } from 'react';

// En lugar de: import HeavyChart from './HeavyChart';
// Carga solo cuando se renderiza:
const HeavyChart = lazy(() => import('./HeavyChart'));
const AdminPanel = lazy(() => import('./AdminPanel'));

Suspense para Estados de Carga

Suspense muestra un respaldo mientras se cargan componentes lazy o datos:

import React, { Suspense, lazy, useState } from 'react';

const HeavyChart = lazy(() => import('./HeavyChart'));

function Dashboard() {
  const [showChart, setShowChart] = useState(false);

  return (
    <div>
      <h1>Panel</h1>
      <Suspense fallback={<p>Cargando...</p>}>
        <DataTable />
      </Suspense>

      <button onClick={() => setShowChart(true)}>Mostrar Grafico</button>
      {showChart && (
        <Suspense fallback={<p>Cargando grafico...</p>}>
          <HeavyChart />
        </Suspense>
      )}
    </div>
  );
}

Combinando Error Boundaries + Suspense

function AsyncBoundary({ children, fallback, errorFallback }) {
  return (
    <ErrorBoundary fallback={errorFallback}>
      <Suspense fallback={fallback}>
        {children}
      </Suspense>
    </ErrorBoundary>
  );
}

// Uso
<AsyncBoundary
  fallback={<LoadingSpinner />}
  errorFallback={(error, retry) => (
    <div>
      <p>Error: {error.message}</p>
      <button onClick={retry}>Reintentar</button>
    </div>
  )}
>
  <Dashboard />
</AsyncBoundary>

✅ Mejores Practicas

  • • Coloca error boundaries en límites significativos de la UI
  • • Siempre proporciona skeletons/placeholders en Suspense
  • • Usa división de código basada en rutas como optimización mínima
  • • Registra errores en un servicio externo (Sentry, LogRocket) en producción
  • • Dale a los usuarios una forma de reintentar o recuperarse de errores