Carga diferida: Suspense y Lazy
Introducción
React.lazy es una función que permite cargar componentes de manera diferida, es decir, solo cuando se necesitan. Esto es especialmente útil para optimizar el rendimiento de tu aplicación al dividir el código (code splitting) y evitar cargar toda la aplicación de una sola vez.
1. Qué es React.lazy? #
React.lazy se usa para cargar componentes dinámicamente en lugar de incluirlos en el paquete inicial. Esto es útil cuando tienes componentes grandes o que no se usan inmediatamente (como rutas o modales).
2. Sintaxis de React.lazy #
1const MiComponente = React.lazy(() => import('./MiComponente'));
React.lazy: Importa el componente de manera diferida.import('./MiComponente'): Devuelve una promesa que React utiliza para cargar el componente dinámicamente.
Nota: Debes usar React.Suspense como envoltorio para manejar el estado de carga mientras el componente se descarga.
3. Ejemplo Básico: Carga Diferida de un Componente #
Paso 1: Crear el Componente #
Crea un componente grande o de carga diferida, por ejemplo: ComponentePesado.js.
1import React from "react"; 2 3function ComponentePesado() { 4 return <h1>Este componente fue cargado de manera diferida</h1>; 5} 6 7export default ComponentePesado;
Paso 2: Usar React.lazy #
En el archivo principal, carga el componente de manera diferida.
1import React, { Suspense, useState } from "react"; 2 3// Importación diferida del componente 4const ComponentePesado = React.lazy(() => import("./ComponentePesado")); 5 6function App() { 7 const [mostrar, setMostrar] = useState(false); 8 9 return ( 10 <div> 11 <h1>Ejemplo con React.lazy</h1> 12 <button onClick={() => setMostrar(!mostrar)}> 13 {mostrar ? "Ocultar" : "Mostrar"} Componente Pesado 14 </button> 15 <Suspense fallback={<p>Cargando...</p>}> 16 {mostrar && <ComponentePesado />} 17 </Suspense> 18 </div> 19 ); 20} 21 22export default App;
Explicación #
React.lazy: Carga el componente solo cuando es necesario (ComponentePesado).Suspense: Muestra un contenido de carga (<p>Cargando...</p>) mientras el componente se descarga.- Estado (
useState): Controlamos cuándo mostrar el componente diferido.
4. Lazy Loading en Rutas con react-router-dom #
Un caso común es cargar componentes diferidos en las rutas de la aplicación.
Ejemplo #
1import React, { Suspense } from "react"; 2import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; 3 4// Carga diferida de componentes 5const Home = React.lazy(() => import("./Home")); 6const About = React.lazy(() => import("./About")); 7 8function App() { 9 return ( 10 <Router> 11 <Suspense fallback={<p>Cargando...</p>}> 12 <Routes> 13 <Route path="/" element={<Home />} /> 14 <Route path="/about" element={<About />} /> 15 </Routes> 16 </Suspense> 17 </Router> 18 ); 19} 20 21export default App;
Explicación #
React.lazy: Cada ruta (HomeyAbout) se carga solo cuando se visita.Suspense: Muestra un indicador de carga mientras se descarga la ruta.
5. Ejemplo Avanzado: Modales con Lazy Loading #
Componente Modal #
Crea un modal como componente diferido.
1// Modal.js 2import React from "react"; 3 4function Modal({ onClose }) { 5 return ( 6 <div style={modalStyles}> 7 <div style={contentStyles}> 8 <h2>Este es un modal</h2> 9 <button onClick={onClose}>Cerrar</button> 10 </div> 11 </div> 12 ); 13} 14 15const modalStyles = { 16 position: "fixed", 17 top: 0, 18 left: 0, 19 width: "100%", 20 height: "100%", 21 backgroundColor: "rgba(0, 0, 0, 0.5)", 22 display: "flex", 23 justifyContent: "center", 24 alignItems: "center", 25}; 26 27const contentStyles = { 28 backgroundColor: "white", 29 padding: "20px", 30 borderRadius: "10px", 31}; 32 33export default Modal;
Usar el Modal con Lazy Loading #
1import React, { useState, Suspense } from "react"; 2 3const Modal = React.lazy(() => import("./Modal")); 4 5function App() { 6 const [mostrarModal, setMostrarModal] = useState(false); 7 8 return ( 9 <div> 10 <h1>Ejemplo de Modal con Lazy Loading</h1> 11 <button onClick={() => setMostrarModal(true)}>Abrir Modal</button> 12 <Suspense fallback={<p>Cargando modal...</p>}> 13 {mostrarModal && <Modal onClose={() => setMostrarModal(false)} />} 14 </Suspense> 15 </div> 16 ); 17} 18 19export default App;
Ventaja #
El modal solo se descarga y renderiza cuando el usuario hace clic en "Abrir Modal", reduciendo el tamaño del paquete inicial.
6. Consideraciones Importantes #
-
Suspensees obligatorio
Siempre usaReact.Suspensepara envolver componentes cargados conReact.lazy. -
Cargar recursos dinámicos
AunqueReact.lazycarga componentes dinámicamente, no incluye estilos ni recursos externos, por lo que debes gestionarlos manualmente. -
Error Boundaries
Usa un Error Boundary para manejar posibles errores durante la carga del componente.
7. Añadiendo un Error Boundary #
React no maneja errores en componentes diferidos automáticamente. Crea un Error Boundary para capturar problemas.
Error Boundary #
1import React from "react"; 2 3class ErrorBoundary extends React.Component { 4 constructor(props) { 5 super(props); 6 this.state = { hasError: false }; 7 } 8 9 static getDerivedStateFromError() { 10 return { hasError: true }; 11 } 12 13 componentDidCatch(error, errorInfo) { 14 console.error("Error capturado:", error, errorInfo); 15 } 16 17 render() { 18 if (this.state.hasError) { 19 return <h1>Algo salió mal.</h1>; 20 } 21 22 return this.props.children; 23 } 24} 25 26export default ErrorBoundary;
Usar Error Boundary #
1import React, { Suspense } from "react"; 2import ErrorBoundary from "./ErrorBoundary"; 3const ComponenteDiferido = React.lazy(() => import("./ComponenteDiferido")); 4 5function App() { 6 return ( 7 <ErrorBoundary> 8 <Suspense fallback={<p>Cargando...</p>}> 9 <ComponenteDiferido /> 10 </Suspense> 11 </ErrorBoundary> 12 ); 13} 14 15export default App;
Resumen del tema
Conceptos clave #
- División de Código (Code Splitting):
React.lazy(() => import('./Componente'))divide el bundle principal en chunks separados descargados solo bajo demanda. - Componente
<Suspense fallback={...}>: obligatorio para envolver componentes diferidos y mostrar una interfaz de espera (spinners, skeletons) durante la descarga del chunk. - Patrón Común con Rutas: diferir páginas enteras en React Router para minimizar el tiempo de carga inicial (First Contentful Paint).
- Manejo de Fallos de Red con Error Boundaries: envolver
<Suspense>con un Error Boundary para capturar y recuperar fallos de red al descargar módulos.
Qué debes recordar #
Usa React.lazy combinado con <Suspense fallback={...}> para diferir la descarga de rutas y componentes pesados reduciendo el bundle inicial.