Реагировать на useCallback
крючок
React useCallback
Hook возвращает запомненную функцию обратного вызова.
Думайте о мемоизации как о кэшировании значения, чтобы его не нужно было пересчитывать.
Это позволяет нам изолировать ресурсоемкие функции, чтобы они не запускались автоматически при каждом рендеринге.
Хук useCallback
запускается только при обновлении одной из его зависимостей.
Это может улучшить производительность.
Крючки useCallback
и useMemo
похожи. Основное отличие состоит в том, что useMemo
возвращает запомненное значение и useCallback
возвращает запомненную функцию . Вы можете узнать больше о useMemo в главе useMemo .
Проблема
Одной из причин использования useCallback
является предотвращение повторного рендеринга компонента, если его свойства не изменились.
В этом примере вы можете подумать, что Todos
компонент не будет повторно отображаться, если todos
изменение:
Это пример, аналогичный приведенному в разделе React.memo .
Пример:
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);
Попробуйте запустить это и нажмите кнопку увеличения счетчика.
Вы заметите, что Todos
компонент перерисовывается, даже если todos
не изменяется.
Почему это не работает? Мы используем memo
, поэтому Todos
компонент не должен повторно рендериться, поскольку ни todos
состояние, ни addTodo
функция не меняются при увеличении счетчика.
Это из-за того, что называется "референтным равенством".
Каждый раз, когда компонент перерисовывается, его функции создаются заново. Из-за этого addTodo
функция фактически изменилась.
Получите сертификат!
ЗАПИСАТЬСЯ НА 95 $
Решение
Чтобы исправить это, мы можем использовать useCallback
хук, чтобы предотвратить повторное создание функции без необходимости.
Используйте useCallback
хук, чтобы предотвратить Todos
ненужный повторный рендеринг компонента:
Пример:
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);
Теперь Todos
компонент будет перерисовываться только при todos
изменении реквизита.