useCallback
useCallback
en React
El hook useCallback
en React se utiliza para memorizar funciones y evitar que se vuelvan a crear en cada renderizado, a menos que cambien las dependencias especificadas. Es útil principalmente cuando pasamos funciones como props a componentes hijos o para optimizar componentes que dependen de referencias estables para no volverse a renderizar innecesariamente.
Sintaxis de useCallback
const memoizedCallback = useCallback(
() => {
// Función que será memorizada
},
[dependencias] // Lista de dependencias
);
memoizedCallback
: Es la función que se memorizó.dependencias
: Lista de variables que, si cambian, hacen queuseCallback
cree una nueva versión de la función.
¿Por qué usar useCallback
?
- Evitar renderizados innecesarios:
- Cuando se pasa una función como prop a un componente hijo, React crea una nueva instancia de la función en cada render. Esto puede llevar a renderizados innecesarios si el hijo está memorizado con
React.memo
.
- Cuando se pasa una función como prop a un componente hijo, React crea una nueva instancia de la función en cada render. Esto puede llevar a renderizados innecesarios si el hijo está memorizado con
- Optimizar rendimiento:
- En aplicaciones grandes o componentes complejos, usar
useCallback
puede ahorrar recursos, especialmente si la función depende de cálculos costosos.
- En aplicaciones grandes o componentes complejos, usar
Ejemplo 1: Evitar funciones recreadas innecesariamente
Código sin useCallback
:
import React from "react";
function Child({ onClick }) {
console.log("Renderizado de Child");
return <button onClick={onClick}>Click me</button>;
}
function Parent() {
const handleClick = () => {
console.log("Botón clickeado");
};
return (
<div>
<h1>Padre</h1>
<Child onClick={handleClick} />
</div>
);
}
export default Parent;
- Cada vez que
Parent
se renderiza,handleClick
se recrea, haciendo que el componenteChild
también se renderice aunque no haya cambios.
Código con useCallback
:
import React, { useCallback } from "react";
function Child({ onClick }) {
console.log("Renderizado de Child");
return <button onClick={onClick}>Click me</button>;
}
function Parent() {
const handleClick = useCallback(() => {
console.log("Botón clickeado");
}, []);
return (
<div>
<h1>Padre</h1>
<Child onClick={handleClick} />
</div>
);
}
export default Parent;
Explicación:
useCallback
memorizó la referencia dehandleClick
, evitando queChild
se vuelva a renderizar innecesariamente.
Ejemplo 2: Uso con dependencias
Código:
import React, { useState, useCallback } from "react";
function Counter() {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
const increment = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []);
const updateText = useCallback(() => {
setText("Nuevo texto");
}, []);
return (
<div>
<h1>Contador: {count}</h1>
<button onClick={increment}>Incrementar</button>
<button onClick={updateText}>Actualizar texto</button>
<p>{text}</p>
</div>
);
}
export default Counter;
Explicación:
increment
yupdateText
se memorizan, por lo que no se recrean en cada render.- Incluso si el estado
count
otext
cambia, estas funciones no se vuelven a crear innecesariamente.
Ejemplo 3: Uso combinado con React.memo
Código:
import React, { useState, useCallback } from "react";
const Child = React.memo(({ onClick }) => {
console.log("Renderizado del hijo");
return <button onClick={onClick}>Hacer algo</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const doSomething = useCallback(() => {
console.log("Acción realizada");
}, []);
return (
<div>
<h1>Contador: {count}</h1>
<button onClick={() => setCount(count + 1)}>Incrementar</button>
<Child onClick={doSomething} />
</div>
);
}
export default Parent;
Explicación:
- El componente
Child
solo se renderiza la primera vez porque su proponClick
es estable gracias auseCallback
. - Aunque
count
cambie,Child
no se vuelve a renderizar.
Ejemplo 4: Evitando cálculos costosos en funciones
Código:
import React, { useState, useCallback } from "react";
function ExpensiveCalculation({ calculate }) {
console.log("Realizando cálculo costoso...");
return <div>Resultado: {calculate()}</div>;
}
function Parent() {
const [input, setInput] = useState("");
const calculate = useCallback(() => {
let result = 0;
for (let i = 0; i < 100000000; i++) {
result += i;
}
return result;
}, []);
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<ExpensiveCalculation calculate={calculate} />
</div>
);
}
export default Parent;
Explicación:
- Sin
useCallback
, la funcióncalculate
se recrearía en cada render, haciendo que el cálculo se ejecute innecesariamente. - Con
useCallback
, el cálculo solo se realiza la primera vez o si las dependencias cambian.
Cuándo usar useCallback
- Cuando pasas funciones a componentes memorizados (
React.memo
). - Cuando tienes funciones costosas que no deben recalcularse innecesariamente.
- Cuando deseas mantener la estabilidad de referencias en hooks como
useEffect
.