Optimizacion de Rendimiento
Memorizacion, code splitting y buenas practicas de React
Rendimiento en React
React es rapido por defecto, pero a medida que tu aplicacion crece, puedes necesitar optimizaciones. Aqui estan las tecnicas mas importantes.
React.memo
import { memo } from 'react';
// Componente que solo se re-renderiza si sus props cambian
const ItemLista = memo(function ItemLista({ titulo, onClick }) {
console.log('Renderizando:', titulo);
return <li onClick={onClick}>{titulo}</li>;
});
// Con comparacion personalizada
const ItemListaPersonalizado = memo(
function ItemLista({ item }) {
return <li>{item.nombre}</li>;
},
(prevProps, nextProps) => {
// Retorna true si no debe re-renderizar
return prevProps.item.id === nextProps.item.id;
}
);
useMemo y useCallback
import { useMemo, useCallback, useState } from 'react';
function ListaFiltrada({ items }) {
const [filtro, setFiltro] = useState('');
const [seleccionado, setSeleccionado] = useState(null);
// Memoriza el resultado del calculo costoso
const itemsFiltrados = useMemo(() => {
return items.filter(item =>
item.nombre.toLowerCase().includes(filtro.toLowerCase())
);
}, [items, filtro]);
// Memoriza la funcion para evitar re-renders de hijos
const handleSeleccionar = useCallback((id) => {
setSeleccionado(id);
}, []);
return (
<div>
<input
value={filtro}
onChange={(e) => setFiltro(e.target.value)}
/>
<ul>
{itemsFiltrados.map(item => (
<ItemLista
key={item.id}
titulo={item.nombre}
onClick={() => handleSeleccionar(item.id)}
/>
))}
</ul>
</div>
);
}
Code Splitting con lazy
import { lazy, Suspense } from 'react';
// Importacion dinamica - el componente se carga solo cuando se necesita
const Dashboard = lazy(() => import('./Dashboard'));
const Configuracion = lazy(() => import('./Configuracion'));
function App() {
return (
<Suspense fallback={<p>Cargando...</p>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/configuracion" element={<Configuracion />} />
</Routes>
</Suspense>
);
}
Virtualizacion de Listas
// npm install @tanstack/react-virtual
import { useVirtualizer } from '@tanstack/react-virtual';
function ListaVirtual({ items }) {
const contenedorRef = useRef(null);
const virtualizador = useVirtualizer({
count: items.length,
getScrollElement: () => contenedorRef.current,
estimateSize: () => 50, // altura estimada de cada item
});
return (
<div ref={contenedorRef} style={{ height: '400px', overflow: 'auto' }}>
<div style={{ height: virtualizador.getTotalSize() }}>
{virtualizador.getVirtualItems().map((itemVirtual) => (
<div
key={itemVirtual.key}
style={{
position: 'absolute',
top: itemVirtual.start,
height: itemVirtual.size,
}}
>
{items[itemVirtual.index].nombre}
</div>
))}
</div>
</div>
);
}
Evitar Errores Comunes
// MAL - Crea nuevo objeto en cada render
<Componente style={{ color: 'red' }} />
// BIEN - Objeto estable
const estilos = { color: 'red' };
<Componente style={estilos} />
// MAL - Crea nueva funcion en cada render
<Boton onClick={() => handleClick(id)} />
// BIEN - Con useCallback
const handleClickMemo = useCallback(() => handleClick(id), [id]);
<Boton onClick={handleClickMemo} />
// MAL - Estado innecesariamente en objeto
const [estado, setEstado] = useState({ nombre: '', email: '' });
// MEJOR - Estados separados si se actualizan independientemente
const [nombre, setNombre] = useState('');
const [email, setEmail] = useState('');
Reglas de Optimizacion
- Mide primero: Usa React DevTools Profiler antes de optimizar
- No optimices prematuramente: Muchas optimizaciones anaden complejidad
- memo para listas: Muy util cuando renderizas muchos items
- Divide componentes: Componentes mas pequenos = re-renders mas precisos