Должен ли я обернуть каждую опору с помощью useCallback или useMemo, когда использовать эти хуки? - PullRequest
9 голосов
/ 23 марта 2019

Теперь с доступными хуками реагирования я должен в случае функциональных компонентов переносить каждую функцию, переданную с реквизитами, с useCallback и всеми другими значениями реквизитов с useMemo ?

ТакжеИмея пользовательскую функцию внутри моего компонента, зависящую от любого значения реквизита, следует ли мне обернуть его useCallback ?

Какова хорошая практика, чтобы решить, какие значения реквизитов или констант из переноса компонента с помощью этих хуков?

Если это улучшает производительность, почему бы не делать это постоянно?

Давайте рассмотрим пользовательскую кнопку, в которую мы помещаем обработчик нажатия, и добавляем пользовательскую логику

function ExampleCustomButton({ onClick }) {
  const handleClick = useCallback(
    (event) => {
      if (typeof onClick === 'function') {
        onClick(event);
      }

      // do custom stuff

    },
    [onClick]
  );

  return <Button onClick={handleClick} />;
}

Давайте рассмотрим пользовательскую кнопку, в которую мы помещаем обработчик клика, и добавляем пользовательскую логику при условии

function ExampleCustomButton({ someBool }) {
  const handleClick = useCallback(
    (event) => {
      if (someBool) {
        // do custom stuff
      }
    },
    [someBool]
  );

  return <Button onClick={handleClick} />;
}

Должен ли я в этих двух случаях обернуть мой обработчик с помощью useCallback ?

Похожиеcase with use memo.

function ExampleCustomButton({ someBool }) {
  const memoizedSomeBool = useMemo(() => someBool, [someBool])
  const handleClick = useCallback(
    (event) => {
      if (memoizedSomeBool) {
        // do custom stuff
      }
    },
    [memoizedSomeBool]
  );

  return <Button onClick={handleClick} />;
}

В этом примере я даже передаю записанное значение в useCallback .

Другой случай, что если в дереве компонентов многие компоненты запоминают одно и то же значение?Как это влияет на производительность?

Ответы [ 2 ]

6 голосов
/ 27 марта 2019

Не стоит, по нескольким причинам:

  1. Даже официальные документы говорят, что вы должны делать это только при необходимости.
  2. Имейте в виду, что преждевременная оптимизация - корень всего зла :)
  3. Это делает DX (опыт разработчика) намного хуже: его труднее читать; труднее писать; сложнее рефакторинг.
  4. При работе с примитивами (как в вашем примере) запоминание требует больше ресурсов процессора, чем бездействие. Примитивное значение не имеет понятия ссылок , поэтому в них нечего запоминать. С другой стороны, само запоминание (как и любой другой хук) требует небольшой обработки, ничего не бесплатно. Несмотря на то, что он крошечный, он все же больше, чем ничего (по сравнению с простым прохождением примитива), так что при таком подходе вы будете стрелять в собственную ногу.

Чтобы сложить все вместе - вы потратите больше времени на набор всех хуков, чем пользователь получит, если они будут размещены в приложении, если вы хотите разместить их повсюду. Применяется старое доброе правило: Измерьте, затем оптимизируйте .

3 голосов
/ 29 марта 2019

Я согласен с принципами, предложенными @ jalooc

Чтобы дать более полное представление о показанных случаях использования в OP, вот мой совет:

Дорогие дети отдают

function Component() {
  const callback = useCallback(() => { dostuff }, [deps])

  return <Child prop={callback} />
}

Вышеуказанное имеет смысл, если Child является очень дорогим компонентом для рендеринга. Как таковой, он, вероятно, экспортируется так:

function Child() { 
   ...this takes significant CPU... 
}

// Export as a pure component
export default React.memo(Child)

Дорогие вычисления

function Component({ foo }) {
  // This very expensive computation will only run when it's input (foo)
  // changes, allowing Component to re-render without performance issues
  const bar = useMemo(() => {
     ... something very complicated with `foo` ...
  }, [foo])

  return <div>{bar}</div>
}

Заключение

  1. Делайте то, что имеет смысл или измеряет плохую производительность
  2. Если функция, изменяющаяся при рендеринге, вызывает производные дорогостоящие вычисления, запомните ее (useCallback) или, если возможно, переместите ее за пределы области действия.
  3. Если сам компонент визуализируется дорого, сделайте его чистым с помощью React.memo, с помощью #2, если необходимо
  4. Если что-то само по себе слишком дорого пересчитать, запомните это (useMemo)
  5. Делайте то, что имеет смысл или измеряет плохую производительность
...