Как стать автором
Обновить

Разница между useMemo и useCallback подробно

Время на прочтение2 мин
Количество просмотров36K

useCallback используется для мемоизации коллбеков в компонентах, а useMemo используется для мемоизации значений. По своей сути, эти два хука ничем не отличаются и предназначение у них одно и тоже - хранение данных. Строение идентичное, как и в useEffect и useLayoutEffect, первым аргументом идёт коллбек и вторым - массив зависимостей.

Вот несколько вопросов:

  • Зачем использовать два метода для одной цели?

  • Почему бы просто не вернуть данные или JSX из useCallback и использовать их?

  • Какая разница между этими двумя методами?

Разница в месте вызова

useMemo вызывается исходниками React'а, а useCallback - нами. Примеры обоих функций:

function memoUsed() {
  const _  = useMemo(() => {
    return ‘insert JSX here’
  })

  return _
}

function callbackUsed() {
  const _  = useCallback(() => {
    return ‘insert JSX here’
  })

  return _()
}

Вуаля, функция useMemo имитирована очень даже прилично, с помощью вызова коллбека (6 и 14 строки). Одна вещь сделана двумя немного разными способами. Дело в том, что в “память” компоненты при пользовании useMemo попадает значение только из return, игнорируя остальное тело функции. В случае с useCallback - коллбек передаётся как строка, без вызова. Но эта разница не влияет на количество маунтов или рендеров компоненты, записи в плане производительности эквивалентны.

В useMemo не рекомендуется использовать другие хуки

Примерчик:

function memoUsed() {
  const [state, setState] = useState(null)

  const _  = useMemo(() => {
    // причинит бесконечный ре-рендер
    setState(‘value’)
    return ‘insert JSX here’
  })

  return _
}

function callbackUsed() {
  const [state, setState] = useState(null)

  const _  = useCallback(() => {
    // обычное дело
    setState(‘value’)
    return ‘insert JSX here’
  })

  return _()
}

При вызове постороннего хука в useMemo и сопутствующем изменении состояния компонента приведёт к зацикливанию. Так как useMemo отрабатывает при стадии рендеринга, модификация состояния компонента запустит процесс заново. С useCallback таких проблем нет, функция вызывается по пользовательскому событию.

В useMemo аргумент-функция не принимает параметры

Ближе к делу:

function memoUsed() {
  const _  = useMemo((arg1) => {
    // React игнорирует аргументы
    return ‘insert JSX here’
  }, [])

  return _
}

function callbackUsed() {
  const _  = useCallback((what, where) => {
    // могут быть использованы в функции
    return ‘insert ${what} ${where}’
  })

  return _(‘JSX’, ‘here’)
}

По документации для useCallback массив зависимостей обязателен

А для useMemo может являться и undefined, что не совсем точно. При отсутствии массива зависимостей в обоих хуках происходит ре-рендер в ста процентах случаев. Это описание является ошибкой, про что заявлено в комментарии в исходном коде.

// allow undefined, but don't make it optional as that is very likely a mistake

В целом, хук useMemo можно заменить судя по всему и существует лишь для абстрактного отделения мемоизации данных от мемоизации методов. Кто знает, может в дальнейших версиях React'a способы хранения данных будут изменяться, так как это очень похоже на наследие классовых компонентов.

Теги:
Хабы:
Всего голосов 12: ↑2 и ↓10-8
Комментарии3

Публикации

Истории

Работа

Ближайшие события

19 марта – 28 апреля
Экспедиция «Рэйдикс»
Нижний НовгородЕкатеринбургНовосибирскВладивостокИжевскКазаньТюменьУфаИркутскЧелябинскСамараХабаровскКрасноярскОмск
22 апреля
VK Видео Meetup 2025
МоскваОнлайн
23 апреля
Meetup DevOps 43Tech
Санкт-ПетербургОнлайн
24 апреля
VK Go Meetup 2025
Санкт-ПетербургОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань
20 – 22 июня
Летняя айти-тусовка Summer Merge
Ульяновская область