Gancio di useCallback
reazione
Il React useCallback
Hook restituisce una funzione di callback memorizzata.
Pensa alla memorizzazione come alla memorizzazione nella cache di un valore in modo che non debba essere ricalcolato.
Questo ci consente di isolare le funzioni ad alta intensità di risorse in modo che non vengano eseguite automaticamente su ogni rendering.
Hook viene eseguito solo quando una delle useCallback
sue dipendenze si aggiorna.
Questo può migliorare le prestazioni.
Gli useCallback
e useMemo
Hooks sono simili. La differenza principale è che useMemo
restituisce un valore memorizzato e useCallback
restituisce una funzione memorizzata . Puoi saperne di più su useMemo nel capitolo useMemo .
Problema
Uno dei motivi per l'utilizzo useCallback
è impedire il re-rendering di un componente a meno che i suoi oggetti di scena non siano cambiati.
In questo esempio, potresti pensare che il Todos
componente non verrà riprodotto a meno che la todos
modifica:
Questo è un esempio simile a quello nella sezione React.memo .
Esempio:
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);
Prova a eseguirlo e fai clic sul pulsante di incremento del conteggio.
Noterai che il Todos
componente esegue nuovamente il rendering anche quando todos
non cambia.
Perché questo non funziona? Stiamo usando memo
, quindi il Todos
componente non dovrebbe essere riprodotto poiché né lo todos
stato né la addTodo
funzione cambiano quando il conteggio viene incrementato.
Ciò è dovuto a qualcosa chiamato "uguaglianza referenziale".
Ogni volta che un componente esegue nuovamente il rendering, le sue funzioni vengono ricreate. Per questo motivo, la addTodo
funzione è effettivamente cambiata.
Ottieni la certificazione!
ISCRIVITI A $95
Soluzione
Per risolvere questo problema, possiamo utilizzare l' useCallback
hook per impedire che la funzione venga ricreata se non necessario.
Utilizzare il useCallback
gancio per evitare che il Todos
componente venga riprodotto inutilmente:
Esempio:
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);
Ora il Todos
componente eseguirà nuovamente il rendering solo quando l' todos
elica cambia.