React Hooks: функциональность setState при повторном рендеринге - PullRequest
0 голосов
/ 13 июня 2019

Это вопрос о возможном падении производительности при использовании хуков. Цитировать useState пример из реагирующих документов:

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
    </>
  );
}

React гарантирует, что идентификатор функции setState стабилен и не изменится при повторном рендеринге. Вот почему безопасно исключить из списка зависимостей useEffect или useCallback.

У меня есть два вопроса относительно использования useState:

  • Что означает identity is stable and won’t change on re-renders? 1014 *
  • Я вижу, что для каждой кнопки функция anonymous передается как обработчик события. Даже если setState identity is stable, как утверждает React, верно, разве анонимная функция не будет создаваться при каждом повторном рендеринге?

Не было бы более эффективно, если бы useCallback использовался для определения запомненных функций и использования их в качестве обработчиков событий?

Ответы [ 3 ]

1 голос
/ 13 июня 2019
  1. Что означает стабильность личности и что она не изменится при повторном рендеринге?

Ваш метод setCount стабилен и не изменится при повторном рендеринге.

  1. Я вижу, что для каждой кнопки анонимная функция передается как обработчик события. Даже если идентичность setState стабильна, как утверждает React, это правда, не будет ли анонимная функция воссоздана при каждом повторном рендеринге?

Вы можете, но здесь нет необходимости делать это, поскольку вы не передаете его дочернему компоненту, вы должны использовать useCallback, если вы передаете его другому компоненту React.

1 голос
/ 13 июня 2019

Что означает, что идентичность стабильна и не изменится при повторном рендеринге?

Функция, возвращаемая useState, не будет меняться в течение циклов рендеринга.То есть функция диспетчеризации, возвращенная в первом цикле рендеринга, все еще может быть вызвана после, скажем, 10-го цикла рендеринга для установки состояния.Это позволяет вам установить хук с помощью функции диспетчеризации в любой точке без необходимости обновлять хук при изменении ссылки на функцию.

  useEffect(() => {
    setCount(initialCount);
  }, [ initialCount, setCount ]); // <--- setCount is not needed here

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

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

Сама функция useCallback имеет длину 20 строк с 3 другими вызовами вложенных функций для других внутренних API React.Все это, чтобы предотвратить создание одной строковой функции на каждом рендере?Математика просто не складывается в пользу useCallback.Единственный полезный сценарий - это когда вы хотите, чтобы ваши обратные вызовы имели «стабильную идентичность» либо по ссылке, либо по какому-либо другому механизму, чтобы вы могли передавать обратный вызов как реквизиты, не вызывая чрезмерных повторных рендерингов.

1 голос
/ 13 июня 2019

Рассмотрим этот компонент как иллюстрацию к вопросу 1.

function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount);

  // after each render we record the value of setCount
  const ref = useRef(null);
  useEffect(() => {
    ref.current = setCount;
  }, [setCount]);

  return (
    <>
      <div>
        Did setCount change from since render?{" "}
        {(!Object.is(ref.current, setCount)).toString()}
      </div>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
    </>
  );
}
  1. Это означает, что во время визуализации различных компонентов useState будет одинаковым (Object.is)

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

Не было бы более эффективно, если бы useCallback использовался для определения запомненных функций и использования их в качестве обработчиков событий?

В данном конкретном случае нет, поскольку useCallback не предоставляется бесплатно, в то время как кнопки будут отображаться в любом случае. Но когда у нас есть очень тяжелый компонент для рендеринга, useCallback предотвратит ненужные повторные рендеры

...