Реакция: обратные вызовы оптимизации с useCallback или без useCallback

#javascript #reactjs #react-hooks #usecallback

#javascript #reactjs #реагирование-перехваты #usecallback

Вопрос:

TL; DR

В некоторых блогах говорится, что вам не нужно использовать useCallback перехват каждый раз, когда вы передаете обратный вызов дочернему компоненту, и иногда лучше каждый раз создавать новую функцию. Потому что стоимость useCallback иногда выше, чем фактическая проблема с производительностью. В то время как React предупреждает, что это может привести к проблемам с производительностью, и мы должны попытаться избежать этого.
Кто прав и каков баланс между этими двумя противоположными утверждениями?

Полный вопрос

В последнее время я читал много блогов и руководств о реактивных перехватах, особенно об useCallback и useMemo .

До React 16 (и всех его перехватов), когда я использую компоненты класса, я всегда использовал «привязку конструктора» для своих обратных вызовов, потому что функция arrow или «Привязка в рендеринге», подобные этим:

 render() {
  return <button onClick={this.handleClick.bind(this)}>Click Me</button>;
}

render() {
  return <button onClick={() => this.handleClick()}>Click Me</button>;
}
  

Рассматривались как «плохая практика». Из React Docs:

Использование Function.prototype.bind при рендеринге создает новую функцию каждый раз при рендеринге компонента, что может повлиять на производительность (см. Ниже).

Использование функции со стрелкой в рендеринге создает новую функцию каждый раз при рендеринге компонента, что может нарушить оптимизацию, основанную на строгом сравнении идентификаторов.

Итак, моим эмпирическим правилом было не передавать новые функции в props.

В React 16 useCallback хук пытается помочь нам сделать именно это. Но я вижу много подобных блогов, в которых утверждается, что вам не нужно использовать useCallback хук каждый раз, потому что стоимость useCallback иногда выше, чем фактическая проблема, и использование функций со стрелками, которые создают новую функцию при каждом рендеринге, подходит.

Оба противоположных утверждения заставили меня подумать, что лучшим вариантом должно быть что-то вроде (если массив зависимостей пуст):

 function handleCallback() { ... } // Or arrow function...

function Foo(props) {
   return <button onClick={handleCallback}>Click Me</button>
}
  

Потому что этот способ не использует «дорогой» useCallback и не генерирует новую функцию каждый раз. Но, на самом деле, этот код выглядит не так хорошо, когда у вас есть несколько обратных вызовов.

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

(Тот же вопрос о эмпирическом правиле «двойные фигурные скобки» и useMemo / useRef hooks)

Комментарии:

1. Ваш подход с function handleCallback внешней стороны Foo компонента, безусловно, оптимален, но не работает, если обратному вызову требуется доступ и реквизиты или состояние.

2. Верно, но когда у вас есть зависимости от состояния или реквизита, вы, вероятно, будете использовать useCallback , потому что его «механизм зависимостей». Интересный случай, когда у вас есть обратный вызов без зависимостей.

3. В этом случае отдельная функция — лучший способ перейти к imo. Я не понимаю, почему вы считаете, что » этот код выглядит не так хорошо «.

4. Когда у вас есть несколько обратных вызовов к одному компоненту, несколько функций в этом файле иногда «скрывают» саму функцию компонента. Ничего страшного… Что-то с useCallback немного более элегантным для меня 🙂