Демистификация хуков React — useCallback

Начиная
Если вы хотите продолжить работу в своей локальной среде IDE, вы можете найти репозиторий GitHub здесь .
clone
cd client
npm i
npm start
Ссылочное равенство — это основополагающая концепция как в JavaScript, так и в компьютерных науках в целом. Итак, начнем с демонстрации его в действии.
Я вставил скриншоты в статью для простоты использования на мобильных устройствах. Если вы находитесь на рабочем столе и клонировали его, запустите referentialEquality.js
, чтобы посмотреть на результат, или просто поиграйте с фрагментом кода JSFiddle, встроенным ниже.
При оценке того, integer 1
является ли строго равным integer 1
, консоль выводит true
. Это потому, что, ну… строго integer 1
равноinteger 1
.

Мы видим тот же результат при оценке двух строк.

Очевидно, что это всегда будет иметь место для двух примитивных типов данных с одним и тем же значением.
А как насчет структур данных? Например, два литерала объекта с одинаковыми парами ключ/значение? Как насчет литералов пустых объектов?

Зачем это печатать false
? При сравнении этих двух литералов объекта строго равны, JavaScript использует их соответствующие адреса памяти .
Другими словами, эти два объекта могут содержать одни и те же значения , но они не ссылаются на один и тот же объект . Они выглядят одинаково, но занимают два разных места в памяти .
То же самое применимо независимо от того, сравниваете ли вы два литерала объекта, два литерала массива или две функции!

Чтобы продемонстрировать это дальше, мы определим функцию func
, которая возвращает анонимную функцию, которая, в свою очередь, возвращает что-то еще ( например, элемент JSX ).

Затем мы назначим две разные функции firstRender
и , secondRender
равные значению, возвращаемому функцией func
.

Думайте о func
своем функциональном компоненте React, в то время как firstRender
это функция внутри него при первом рендеринге и secondRender
функция внутри него при втором рендеринге.
Несмотря на то, что firstRender
и secondRender
возвращают одно и то же значение и присваиваются из одного и того же определения, они не имеют ссылочного равенства . В результате каждый раз, когда компонент отрисовывается, он переопределяет эту функцию.

К сожалению, в JavaScript не так просто напечатать эти адреса памяти, как в Python, но более подробное объяснение ссылки и значения можно найти в этой статье на сайте freeCodeCamp.
Эта тема может стать сложной, и вам не нужно вести по ней класс сегодня вечером. Итак, пока просто запомните:
- примитивный тип данных
===
примитивный тип данных - структура данных
!==
структура данных.
Стартовый код
После того, как мы раскрутим наше приложение, откройте BookDetails.jsx
компонент и сохраните его заново. Первое, что мы можем заметить на нашем сервере разработки React, — это то WARNING
, что молодые разработчики склонны игнорировать. Когда вы наберетесь рабочей силы и начнете писать код для производства, ваши линтеры будут еще более строгими, чем то, что встроено в create-react-app
. WARNINGS
обратятся к ERRORS
, а некоторые линтеры не позволят вам нажать перед тем, как вы обратитесь к этим ERRORS
.
Поэтому вместо того, чтобы игнорировать это, давайте выясним, как с этим бороться.

ПРИМЕЧАНИЕ. Сначала вам может потребоваться повторное сохранение BookDetails.jsx
, чтобы создать этотWARNING
Если мы покопаемся в React Docs , мы сможем расшифровать полузапутанные предлагаемые решения следующим образом WARNING
:
1. Включите определение функции в файл useEffect
.
- Мы не можем вызывать эту функцию в другом месте, пока не переопределим ее.
- Это вызовет
useEffect
постоянное изменение состояния или реквизита, иногда вызывая бесконечный повторный рендеринг. И в нашем случае, поскольку мы вызываем нашу функцию установки состояния после вызова API, это может перегрузить наш API бесконечными запросами конечной точки.
- Функция не будет вызываться.
- При первом рендеринге компонента он определит нашу функцию, которая вызовет
useEffect
, что приведет к повторному рендерингу компонента, что переопределит функцию, которая вызоветuseEffect
, что приведет к повторному рендерингу компонента, что переопределит функцию…
Самым простым и предпочтительным решением было бы «включить его», то есть переместить getBookDetails
определение функции внутрь файла useEffect
. Это соответствует принципу объектно-ориентированного программирования, известному как инкапсуляция .
Но допустим, мы знаем, что нам нужно вызвать функцию в другом месте. Должны ли мы переопределить его позже? Это не очень СУХО с нашей стороны.
Давайте изменим наш массив зависимостей, чтобы включить ссылку на нашу функцию. Теперь вы useEffect
должны выглядеть так.

И getBookDetails
остается определенным над .useEffect

Теперь у нас есть новыйWARNING

Введите хук useCallback
Короче говоря, useCallback
хук позволяет вам кэшировать или «запоминать» функцию между повторными рендерингами вашего компонента. Он выполняет ту же задачу useMemo
, что и , нюансы которой мы рассмотрим в другой статье.
Если вас интересуют подробности этого, вы можете прочитать больше в документации React .
Обратите внимание на их предупреждение:
Вы должны полагаться только useCallback
на оптимизацию производительности. Если ваш код не работает без него, сначала найдите основную проблему и устраните ее. Затем вы можете добавить useCallback
, чтобы улучшить производительность.
useCallback
Синтаксис
useCallback
Синтаксис 's очень похож на useEffect
синтаксис '', который мы уже знаем. Посмотрите на скелеты каждого.

Небольшая разница заключается в том useEffect
, что с помощью мы сообщаем анонимной функции о выполнении нашей функции , а с помощью useCallback
мы присваиваем возвращаемое значение ссылке, которая будет вызываться в другом месте.
Использование обратного вызова
Во-первых, мы будем импортировать useCallback
из 'react'
. Вместо того, чтобы добавлять новую строку, лучше удалить ее вместе с другими импортируемыми данными.

Теперь мы можем присвоить getBookDetails
значение, возвращаемое useCallback
вызовом функции.

Затем мы добавляем весь синтаксис для useCallback
. Помните свой массив зависимостей!

В нашем примере нам нужно async
перед нашими параметрами.

И, наконец, мы добавляем логику нашей функции в блок кода.

Как только мы сохраним, мы получим… еще один WARNING
.

Почему наш массив зависимостей должен отслеживать id
переменную?
Давайте обдумаем это.
- Если значение
id
изменяется,getBookDetails
необходимо попасть в другую конечную точку, поэтому React должен переопределить ее. ОпределениеgetBookDetails
буквально зависит от значенияid
.

И, наконец, это все! Мы видим зеленый цвет на нашем сервере разработки React. Счастливый линтер — это счастливый старший разработчик. А счастливый Senior Developer — это счастливый ты!
Я всегда ищу новых друзей и коллег. Если вы нашли эту статью полезной и хотели бы связаться, вы можете найти меня в любом из моих домов в Интернете.
Гитхаб | Твиттер | Линкедин | Веб-сайт
Ресурсы
- Ссылочное равенство
- Примитивные типы данных JavaScript и структуры данных
- Инкапсуляция
useCallback
- Реагировать Документы