Reaguj useCallback
hak
React useCallback
Hook zwraca zapamiętaną funkcję zwrotną.
Pomyśl o zapamiętywaniu jako buforowaniu wartości, aby nie trzeba było jej ponownie obliczać.
To pozwala nam odizolować funkcje wymagające dużej ilości zasobów, aby nie uruchamiały się automatycznie przy każdym renderowaniu.
Hook działa tylko wtedy useCallback
, gdy jedna z jego zależności zostanie zaktualizowana.
Może to poprawić wydajność.
The useCallback
i useMemo
Hooki są podobne. Główna różnica polega na tym, że useMemo
zwraca zapamiętaną wartość i useCallback
zwraca zapamiętaną funkcję . Więcej informacji o useMemo znajdziesz w rozdziale useMemo .
Problem
Jednym z powodów użycia useCallback
jest zapobieganie ponownemu renderowaniu komponentu, chyba że jego właściwości uległy zmianie.
W tym przykładzie możesz pomyśleć, że Todos
składnik nie zostanie ponownie wyrenderowany, chyba że todos
zmiana:
Jest to podobny przykład do tego w sekcji React.memo .
Przykład:
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);
Spróbuj uruchomić to i kliknij przycisk zwiększania liczby.
Zauważysz, że Todos
składnik jest ponownie renderowany, nawet jeśli todos
nie ulegną zmianie.
Dlaczego to nie działa? Używamy memo
, więc Todos
komponent nie powinien być ponownie renderowany, ponieważ ani todos
stan, ani addTodo
funkcja nie zmieniają się, gdy liczba jest zwiększana.
Dzieje się tak z powodu czegoś, co nazywa się „równością referencyjną”.
Za każdym razem, gdy komponent jest ponownie renderowany, jego funkcje są odtwarzane. Z tego powodu addTodo
funkcja faktycznie się zmieniła.
Zostać certyfikowanym!
95 $ ZAPISZ
Rozwiązanie
Aby to naprawić, możemy użyć useCallback
zaczepu, aby zapobiec ponownemu utworzeniu funkcji, chyba że jest to konieczne.
Użyj useCallback
zaczepu, aby zapobiec Todos
niepotrzebnemu ponownemu renderowaniu komponentu:
Przykład:
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);
Teraz Todos
komponent będzie ponownie renderowany tylko wtedy, gdy todos
zmieni się właściwość.