Curso react nivel medio
Introducción
En React, el hook useMemo se utiliza para memorizar valores calculados, optimizando el rendimiento de componentes funcionales. Esto es especialmente útil cuando tienes cálculos complejos o costosos que no necesitan ejecutarse en cada renderización.
¿Qué es useMemo?
useMemo memoriza el resultado de una función de cálculo y solo la vuelve a ejecutar cuando cambian sus dependencias. Esto ayuda a evitar cálculos innecesarios.
Sintaxis
1const valorMemoizado = useMemo(() => { 2 return computaciónPesada(); 3}, [dependencias]);
-
useMemorecibe dos argumentos:- Función de cálculo: Devuelve el valor que se memorizará.
- Array de dependencias: Cuando alguna de estas dependencias cambia, la función se vuelve a ejecutar.
-
valorMemoizado: Es el resultado de la función de cálculo, que será reutilizado hasta que las dependencias cambien.
Caso Básico: Cálculo Costoso
Sin useMemo
1import React, { useState } from "react"; 2 3function CalculoPesado({ valor }) { 4 const calcular = () => { 5 console.log("Calculando..."); 6 let suma = 0; 7 for (let i = 0; i < 1000000000; i++) { 8 suma += valor; 9 } 10 return suma; 11 }; 12 13 return <p>Resultado: {calcular()}</p>; 14} 15 16function App() { 17 const [contador, setContador] = useState(0); 18 19 return ( 20 <div> 21 <button onClick={() => setContador(contador + 1)}>Incrementar</button> 22 <CalculoPesado valor={contador} /> 23 </div> 24 ); 25} 26 27export default App;
Problema
Cada vez que haces clic en "Incrementar", la función calcular se ejecuta de nuevo, incluso si no ha cambiado el valor necesario.
Con useMemo
1import React, { useState, useMemo } from "react"; 2 3function CalculoPesado({ valor }) { 4 const resultadoMemoizado = useMemo(() => { 5 console.log("Calculando..."); 6 let suma = 0; 7 for (let i = 0; i < 1000000000; i++) { 8 suma += valor; 9 } 10 return suma; 11 }, [valor]); 12 13 return <p>Resultado: {resultadoMemoizado}</p>; 14} 15 16function App() { 17 const [contador, setContador] = useState(0); 18 19 return ( 20 <div> 21 <button onClick={() => setContador(contador + 1)}>Incrementar</button> 22 <CalculoPesado valor={contador} /> 23 </div> 24 ); 25} 26 27export default App;
Ventaja
La función calcular solo se ejecuta cuando valor cambia, mejorando el rendimiento.
Caso Práctico: Filtrar una Lista
Sin useMemo
1import React, { useState } from "react"; 2 3function App() { 4 const [filtro, setFiltro] = useState(""); 5 const usuarios = ["Ana", "Juan", "Carlos", "Sofía", "María"]; 6 7 const usuariosFiltrados = usuarios.filter((usuario) => 8 usuario.toLowerCase().includes(filtro.toLowerCase()) 9 ); 10 11 return ( 12 <div> 13 <input 14 type="text" 15 placeholder="Buscar..." 16 value={filtro} 17 onChange={(e) => setFiltro(e.target.value)} 18 /> 19 <ul> 20 {usuariosFiltrados.map((usuario, index) => ( 21 <li key={index}>{usuario}</li> 22 ))} 23 </ul> 24 </div> 25 ); 26} 27 28export default App;
Problema
El filtrado de la lista se recalcula en cada render, incluso si el filtro no cambia.
Con useMemo
1import React, { useState, useMemo } from "react"; 2 3function App() { 4 const [filtro, setFiltro] = useState(""); 5 const usuarios = ["Ana", "Juan", "Carlos", "Sofía", "María"]; 6 7 const usuariosFiltrados = useMemo(() => { 8 console.log("Filtrando usuarios..."); 9 return usuarios.filter((usuario) => 10 usuario.toLowerCase().includes(filtro.toLowerCase()) 11 ); 12 }, [filtro]); 13 14 return ( 15 <div> 16 <input 17 type="text" 18 placeholder="Buscar..." 19 value={filtro} 20 onChange={(e) => setFiltro(e.target.value)} 21 /> 22 <ul> 23 {usuariosFiltrados.map((usuario, index) => ( 24 <li key={index}>{usuario}</li> 25 ))} 26 </ul> 27 </div> 28 ); 29} 30 31export default App;
Ventaja
La lista de usuarios solo se filtra cuando cambia el valor de filtro.
Caso Complejo: Tabla con Cálculos Derivados
Ejemplo
1import React, { useState, useMemo } from "react"; 2 3function App() { 4 const [datos, setDatos] = useState([ 5 { nombre: "Producto A", precio: 50, cantidad: 2 }, 6 { nombre: "Producto B", precio: 30, cantidad: 4 }, 7 { nombre: "Producto C", precio: 20, cantidad: 5 }, 8 ]); 9 10 const total = useMemo(() => { 11 console.log("Calculando total..."); 12 return datos.reduce((suma, item) => suma + item.precio * item.cantidad, 0); 13 }, [datos]); 14 15 return ( 16 <div> 17 <h1>Lista de Productos</h1> 18 <ul> 19 {datos.map((item, index) => ( 20 <li key={index}> 21 {item.nombre}: ${item.precio} x {item.cantidad} 22 </li> 23 ))} 24 </ul> 25 <h2>Total: ${total}</h2> 26 </div> 27 ); 28} 29 30export default App;
Ventaja
El cálculo del total solo se ejecuta cuando cambian los datos.
Consideraciones
-
useMemoNo es Siempre Necesario
Solo úsalo cuando los cálculos sean costosos y afecten el rendimiento. -
Evitar Arrays de Dependencias Vacíos
Si el array de dependencias está vacío ([]), la función solo se ejecutará una vez, lo cual puede ser útil en algunos casos, pero asegúrate de que sea lo que necesitas. -
Memoria vs. Rendimiento
Memorizar cálculos consume algo de memoria. Úsalo sabiamente para encontrar el balance entre rendimiento y consumo de recursos.
Conclusión
useMemo es una herramienta poderosa para optimizar el rendimiento de componentes React al evitar cálculos innecesarios. Es ideal para:
- Cálculos complejos.
- Filtrado y mapeo de grandes datasets.
- Casos donde las dependencias cambian con poca frecuencia.