Gancho de useCallback
reação
O React useCallback
Hook retorna uma função de retorno de chamada memorizada.
Pense na memoização como o armazenamento em cache de um valor para que ele não precise ser recalculado.
Isso nos permite isolar funções com uso intensivo de recursos para que elas não sejam executadas automaticamente em cada renderização.
O useCallback
Hook só é executado quando uma de suas dependências é atualizada.
Isso pode melhorar o desempenho.
Os ganchos useCallback
e são semelhantes. useMemo
A principal diferença é que useMemo
retorna um valor memorizado e useCallback
retorna uma função memorizada . Você pode aprender mais sobre useMemo no capítulo useMemo .
Problema
Um motivo para usar useCallback
é evitar que um componente seja renderizado novamente, a menos que suas props sejam alteradas.
Neste exemplo, você pode pensar que o Todos
componente não será renderizado novamente, a menos que a todos
alteração:
Este é um exemplo semelhante ao da seção React.memo .
Exemplo:
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);
Tente executar isso e clique no botão de incremento de contagem.
Você notará que o Todos
componente é renderizado novamente mesmo quando todos
não muda.
Por que isso não funciona? Estamos usando memo
, portanto, o Todos
componente não deve renderizar novamente, pois nem o todos
estado nem a addTodo
função mudam quando a contagem é incrementada.
Isso é por causa de algo chamado "igualdade referencial".
Toda vez que um componente é renderizado novamente, suas funções são recriadas. Por causa disso, a addTodo
função realmente mudou.
Obter certificação!
$ 95 INSCRIÇÃO
Solução
Para corrigir isso, podemos usar o useCallback
gancho para impedir que a função seja recriada, a menos que seja necessário.
Use o useCallback
Hook para evitar que o Todos
componente seja renderizado novamente desnecessariamente:
Exemplo:
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);
Agora, o Todos
componente só será renderizado novamente quando o todos
prop mudar.