Реагировать Учебник

Реагировать Главная Реагировать Введение Реагировать Начать Реагировать ES6 Реагировать на визуализацию HTML Реагировать JSX Реагировать Компоненты Реагировать на класс Реагировать на реквизиты Реагировать на события Реагировать на условия Реагировать списки Реагировать на формы Реактивный маршрутизатор Реагировать на заметку Реагировать на стили CSS Реагировать на стиль Sass

Реагировать на крючки

Что такое крючок? использование состояния использованиеЭффект использованиеконтекста useRef использованиередьюсер использоватьОбратный звонок useMemo Пользовательские крючки

Упражнения по реагированию

Ответная викторина Упражнения по реагированию Сертификат реакции

Реагировать на useCallbackкрючок


React useCallbackHook возвращает запомненную функцию обратного вызова.

Думайте о мемоизации как о кэшировании значения, чтобы его не нужно было пересчитывать.

Это позволяет нам изолировать ресурсоемкие функции, чтобы они не запускались автоматически при каждом рендеринге.

Хук 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функция фактически изменилась.


w3schools CERTIFIED . 2022

Получите сертификат!

Завершите модули React, выполните упражнения, сдайте экзамен и получите сертификат w3schools!!

ЗАПИСАТЬСЯ НА 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изменении реквизита.