Volver a React Básico
Rendimiento en React
React re-renderiza componentes cuando el estado o las props cambian. Las siguientes herramientas permiten omitir re-renderizados innecesarios.
React.memo
Memoriza el resultado del renderizado de un componente:
import { memo } from 'react';
interface Props {
nombre: string;
onClick: () => void;
}
// Solo re-renderiza si `nombre` u `onClick` cambian
const TarjetaUsuario = memo(function TarjetaUsuario({ nombre, onClick }: Props) {
console.log("Renderizando TarjetaUsuario");
return <div onClick={onClick}>{nombre}</div>;
});
useCallback
Memoriza una función para mantener la misma referencia entre renderizados:
import { useState, useCallback, memo } from 'react';
const Boton = memo(({ onClick, label }: { onClick: () => void; label: string }) => {
console.log("Botón renderizado:", label);
return <button onClick={onClick}>{label}</button>;
});
function Contador() {
const [cuenta, setCuenta] = useState(0);
const [otro, setOtro] = useState(0);
// Sin useCallback: nueva función en cada renderizado → Botón siempre re-renderiza
// Con useCallback: misma función referencia → Botón NO re-renderiza cuando `otro` cambia
const incrementar = useCallback(() => setCuenta(c => c + 1), []);
return (
<>
<Boton onClick={incrementar} label={`Cuenta: ${cuenta}`} />
<button onClick={() => setOtro(n => n + 1)}>Otro: {otro}</button>
</>
);
}
useMemo
Memoriza el resultado de un cálculo costoso:
import { useState, useMemo } from 'react';
function ListaFiltrada({ items }: { items: string[] }) {
const [filtro, setFiltro] = useState('');
// Solo recalcula cuando `items` o `filtro` cambian
const filtrados = useMemo(() => {
console.log("Filtrando...");
return items.filter(item => item.toLowerCase().includes(filtro.toLowerCase()));
}, [items, filtro]);
return (
<>
<input value={filtro} onChange={e => setFiltro(e.target.value)} placeholder="Filtrar..." />
<ul>{filtrados.map(item => <li key={item}>{item}</li>)}</ul>
</>
);
}
Carga Diferida con lazy y Suspense
import { lazy, Suspense } from 'react';
// El componente solo se carga cuando se necesita
const Tablero = lazy(() => import('./pages/Tablero'));
const Configuracion = lazy(() => import('./pages/Configuracion'));
function App() {
return (
<Suspense fallback={<div className="spinner">Cargando...</div>}>
<Routes>
<Route path="/tablero" element={<Tablero />} />
<Route path="/config" element={<Configuracion />} />
</Routes>
</Suspense>
);
}
Guía de Rendimiento
| Herramienta | Cuándo usar |
|---|---|
React.memo | Un componente hijo re-renderiza con las mismas props |
useCallback | Pasas callbacks a componentes memorizados |
useMemo | Cálculo costoso que depende de pocas dependencias |
lazy() | Rutas o modales grandes que no se necesitan de inmediato |
Regla general: No optimices prematuramente. Primero perfila con las DevTools de React y luego aplica estas herramientas donde hay cuellos de botella reales.