Gancho de useCallback
reacción
React useCallback
Hook devuelve una función de devolución de llamada memorizada.
Piense en la memorización como el almacenamiento en caché de un valor para que no sea necesario volver a calcularlo.
Esto nos permite aislar las funciones que consumen muchos recursos para que no se ejecuten automáticamente en cada renderizado.
El useCallback
Hook solo se ejecuta cuando se actualiza una de sus dependencias.
Esto puede mejorar el rendimiento.
Los ganchos useCallback
y useMemo
son similares. La principal diferencia es que useMemo
devuelve un valor memorizado y useCallback
devuelve una función memorizada . Puede obtener más información sobre useMemo en el capítulo useMemo .
Problema
Una razón para usarlo useCallback
es evitar que un componente se vuelva a renderizar a menos que sus accesorios hayan cambiado.
En este ejemplo, podría pensar que el Todos
componente no se volverá a procesar a menos que todos
cambie:
Este es un ejemplo similar al de la sección React.memo .
Ejemplo:
index.js
import { useState } from "react";
import ReactDOM from "react-dom";
import Todos from "./Todos";
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};
return (
<>
<Todos todos={todos} addTodo={addTodo} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
Todos.js
import { memo } from "react";
const Todos = ({ todos, addTodo }) => {
console.log("child render");
return (
<>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</>
);
};
export default memo(Todos);
Intente ejecutar esto y haga clic en el botón de incremento de conteo.
Notará que el Todos
componente se vuelve a renderizar incluso cuando todos
no cambia.
¿Por qué esto no funciona? Estamos usando memo
, por lo que el Todos
componente no debería volver a renderizarse ya que ni el todos
estado ni la addTodo
función cambian cuando se incrementa el conteo.
Esto se debe a algo llamado "igualdad referencial".
Cada vez que se vuelve a renderizar un componente, se recrean sus funciones. Debido a esto, la addTodo
función en realidad ha cambiado.
¡Obtener la certificación!
$95 INSCRÍBETE
Solución
Para solucionar esto, podemos usar el useCallback
gancho para evitar que la función se vuelva a crear a menos que sea necesario.
Use el useCallback
gancho para evitar que el Todos
componente se vuelva a renderizar innecesariamente:
Ejemplo:
index.js
import { useState, useCallback } from "react";
import ReactDOM from "react-dom";
import Todos from "./Todos";
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = useCallback(() => {
setTodos((t) => [...t, "New Todo"]);
}, [todos]);
return (
<>
<Todos todos={todos} addTodo={addTodo} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
Todos.js
import { memo } from "react";
const Todos = ({ todos, addTodo }) => {
console.log("child render");
return (
<>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</>
);
};
export default memo(Todos);
Ahora el Todos
componente solo se volverá a renderizar cuando todos
cambie la propiedad.