Что такое hook react
Краткий обзор хуков
Хуки — нововведение в React 16.8, которое позволяет использовать состояние и другие возможности React без написания классов.
Хуки — обратно совместимы. На этой странице вы получите общее представление о хуках. Имейте в виду, что это беглый обзор, который больше подойдёт опытным пользователям React. В конце каждого раздела есть вот такой жёлтый блок с детальным объяснением на случай, если вы запутались:
Если вы хотите понять, почему мы добавляем хуки в React, прочтите мотивацию.
Рассмотрим пример, в котором рендерится счётчик. Если вы нажмёте на кнопку, значение счётчика будет инкрементировано.
В этом примере, useState — это хук (определение хука дано ниже). Мы вызываем его, чтобы наделить наш функциональный компонент внутренним состоянием. React будет хранить это состояние между рендерами. Вызов useState возвращает массив с двумя элементами, который содержит: текущее значение состояния и функцию для его обновления. Эту функцию можно использовать где угодно, например, в обработчике событий. Она схожа с this.setState в классах, но не сливает новое и старое состояние вместе. Сравнение хука useState и this.state приводится на странице Использование хука состояния.
Объявление нескольких переменных состояния
Хук состояния можно использовать в компоненте более одного раза.
Хуки — это функции, с помощью которых вы можете «подцепиться» к состоянию и методам жизненного цикла React из функциональных компонентов. Хуки не работают внутри классов — они дают вам возможность использовать React без классов. (Мы не рекомендуем сразу же переписывать существующие компоненты, но при желании, вы можете начать использовать хуки в своих новых компонентах.)
Вам скорее всего доводилось ранее запрашивать данные, делать подписки или вручную менять DOM из React-компонента. Мы расцениваем эти операции как «побочные эффекты» (или сокращённо «эффекты»), так как они могут влиять на работу других компонентов и их нельзя выполнить во время рендера.
К примеру, этот компонент устанавливает заголовок документа после того, как React обновляет DOM:
При необходимости вы можете вернуть из эффекта функцию, которая указывает эффекту, как выполнить за собой «сброс». Например, этот компонент использует эффект, чтобы подписаться на статус друга в сети, и выполняет сброс, отписываясь от него.
Хуки дают вам возможность организовать побочные эффекты в компоненте по связанным частям (например, добавление или отмена подписки), вместо того, чтобы принуждать вас делить всё согласно методам жизненного цикла.
Вы можете узнать больше о useEffect на странице Использование хука эффекта.
Хуки — это функции JavaScript, которые налагают два дополнительных правила:
Мы разработали специальный плагин для линтера, который помогает обеспечивать соблюдение этих правил. Мы понимаем, что эти правила могут показаться немного непонятными и накладывать определённые ограничения, но они очень важны для правильной работы хуков.
Вы можете узнать больше на странице Правила хуков.
💡 Создание собственных хуков
Иногда нужно повторно использовать одинаковую логику состояния в нескольких компонентах. Традиционно использовались два подхода: компоненты высшего порядка и рендер-пропсы. С помощью пользовательских хуков эта задача решается без добавления ненужных компонентов в ваше дерево.
Прежде всего, давайте извлечём эту логику в пользовательский хук useFriendStatus
Хук принимает friendID в качестве аргумента и возвращает переменную, которая показывает, в сети наш друг или нет.
Теперь мы можем использовать этот хук в обоих наших компонентах:
Состояния каждого компонента никаким образом не зависят друг от друга. Хуки — это способ использовать повторно логику состояния, а не само состояние. Более того, каждое обращение к хуку обеспечивает совершенно изолированное состояние. Вы даже можете использовать один и тот же хук несколько раз в одном компоненте.
Пользовательские хуки — это в большей степени соглашение, чем дополнение. Если имя функции начинается с ” use ” и она вызывает другие хуки, мы расцениваем это как пользовательский хук. Если вы будете придерживаться соглашения useSomething при именовании хуков, это позволит нашему плагину для линтера найти баги в коде, который использует хуки.
Есть много подходящих случаев, чтобы написать пользовательские хуки, такие как работа с формами, анимация, декларативные подписки, таймеры и, наверное, много других, о которых мы даже не думали. Мы с нетерпением ожидаем увидеть, какие же пользовательские хуки сообщество React сможет придумать.
А хук useReducer даёт возможность управлять внутренним состоянием более сложного компонента с помощью редюсера.
Вы можете узнать больше обо всех встроенных хуках на странице API-справочника хуков.
Фух, давайте перестанем торопиться и немного охладим пыл! Если вам что-то непонятно или вы хотите узнать о чём-либо более подробно, вы можете начать читать следующие страницы, начиная с документации хука состояния.
Вы также можете просмотреть API-справочник хуков и FAQ хуков.
И наконец, не проходите мимо вступительной страницы, на которой вы узнаете почему мы добавляем хуки и как мы планируем использовать их вместе с классами без необходимости переписывать наши приложения.
Вопросы для собеседования по хукам React
Что такое хуки в React?
Будут ли хуки React работать внутри классовых компонентов?
Зачем были введены хуки в React?
Одной из причин введения хуков была сложность работы с ключевым словом this внутри классовых компонентов. Если с ним не обращаться должным образом, this будет иметь несколько другое значение. Это приведет к поломке таких строк, как this.setState() и других обработчиков событий. Используя хуки, мы избегаем этой сложности при работе с функциональными компонентами.
Классовые компоненты не очень хорошо минимизируются, а также делают горячую перезагрузку ненадежной. Это еще одна причина для создания хуков.
Другая причина в том, что не существует конкретного способа повторно использовать логику компонента, наделенного состоянием. Несмотря на то, что HOC (Higher-Order Component) и шаблоны Render Props (метод передачи props от родителя ребенку, используя функцию или замыкание) решают эту проблему, здесь требуется изменить код классового компонента. Хуки позволяют совместно использовать логику с отслеживанием состояния без изменения иерархии компонентов.
Четвертая причина заключается в том, что в сложном классовом компоненте связанный код разбросан по разным методам жизненного цикла. Например, в случае загрузки данных (fetch) мы делаем это в основном в componentDidMount() и componentDidUpdate(). Другой пример: в случае слушателей событий мы используем componentDidMount() для подписки на события и componentWillUnmount() для отмены подписки. Вместо этого хуки помогают объединить связанный код.
Как работает хук useState? Какие аргументы принимает этот хук и что он возвращает?
Сначала мы импортируем useState из React
Затем мы используем useState, например:
Задача на использование useState
У нас есть классовый компонент с состоянием. Каждый раз, когда нажимается кнопка в компоненте, счетчик увеличивается.
Перепишите этот компонент, используя хуки React.
Решение
Задача на использование useState 2
Ниже у нас есть классовый компонент. Он содержит код для обновления состояния на основе предыдущего значения состояния.
Перепишите вышеуказанный код, используя хуки React.
Решение.
Можно обновить значение переменной состояния, просто передав новое значение в функцию обновления или передав callback. Второй способ с передачей callback-функции безопасен в использовании.
Задача на использование useState 3
Здесь у нас есть классовый компонент, который обновляет состояние, используя ввод из формы.
Перепишите этот компонент, используя хуки React.
Решение
Функция обновления состояния в useState() не выполняет автоматическое слияние, если в состоянии хранится объект. Но в случае использования метода setState() в классовых компонентах происходит автоматическое слияние.
Здесь мы объединяем свойства объекта с помощью spread оператора JavaScript.
Каковы различия в использовании хуков и классовых компонентов в отношении управления состоянием?
При использовании setState() в классовых компонентах переменная состояния всегда является объектом. В то время как переменная состояния в хуках может иметь любой тип, например, число, строку, логическое значение, объект или массив.
Когда переменная состояния является объектом, setState() в классовых компонентах автоматически объединяет новое значение с объектом состояния. Но в случае функции обновления состояния в useState() нам нужно явно объединить обновленное свойство объекта с помощью spread оператора.
Зачем нужен хук useEffect?
Хук useEffect позволяет нам выполнять побочные эффекты в функциональных компонентах. Это помогает нам избежать избыточного кода в различных методах жизненного цикла классового компонента. Это помогает сгруппировать связанный код.
Задача на использование useEffect
Вот классовый компонент, который печатает Boom в консоли каждый раз, когда он монтируется или обновляется.
Удалите избыточные выражения console.log с помощью хуков React.
Решение.
Код может быть переписан таким образом:
Задача на использование useEffect 2
Код печатает сообщение «Счетчик обновлен» даже при обновлении значения в текстовом поле. Как мы можем отображать сообщение только при обновлении состояния счетчика?
Решение.
Функция useEffect принимает второй параметр, который должен быть массивом. В этом массиве нам нужно передать props или состояние, за которым нам нужно следить. Эффект выполняется только в том случае, если эти свойства или состояние, упомянутые в массиве, изменяются. Поэтому в нашем коде мы добавляем второй аргумент и указываем только значение count в массиве.
Вот обновленный код useEffect:
Задача на использование useEffect 3
У нас есть классовый компонент, который обновляет время каждую секунду. Он использует componentDidMount() для установки таймера.
Перепишите код выше с помощью хуков React.
Решение.
Вот код с использованием хуков React.
Задача на использование useEffect 4
У нас есть фрагмент кода из классового компонента, который регистрирует и удаляет слушатель событий.
Перепишите этот код в стиле хуков React.
Решение.
Чтобы использовать функциональность метода жизненного цикла componentWillUnmount() в хуке useEffect нужно вернуть callback с кодом, который необходимо выполнить при размонтировании компонента.
Задача на использование useContext
Вот фрагмент кода из компонента Context.Consumer.
Перепишите ConsumerComponent, используя хук useContext.
Решение.
Хуки можно использовать только в функциональном компоненте.
ConsumerComponent можно переписать так:
Заметка о том, как работают хуки в React
Доброго времени суток, друзья!
Хочу поделиться с вами некоторыми наблюдениями относительно того, как работает React, а именно: предположениями о том, почему хуки нельзя использовать в if, циклах, обычных функциях и т.д. И действительно ли их нельзя использовать подобным образом?
Вопрос звучит следующим образом: почему хуки можно использовать только на верхнем уровне? Вот что по этому поводу говорит официальная документация.
Начнем с правил использования хуков.
Используйте хуки только на верхнем уровне (выделил ключевые моменты, на которые следует обратить внимание):
«Не вызывайте хуки внутри циклов, условных операторов или вложенных функций. Вместо этого всегда используйте хуки только внутри React-функций, до возврата какого-либо значения из них. Исполнение этого правила гарантирует, что хуки вызываются в одинаковой последовательности при каждом рендере компонента. Это позволит React правильно сохранять состояние хуков между множественными вызовами useState и useEffect. (Если вам интересно, подробное объяснение ниже.)»
Нам интересно, смотрим ниже.
Объяснение (примеры опущены для краткости):
Понятно? Да как-то не очень. Что значит «React полагается на порядок вызова хуков»? Как он это делает? Что за «некое внутреннее состояние»? К каким ошибкам приводит пропуск хука при повторном рендере? Являются ли эти ошибки критическими для работы приложения?
Есть ли в документации что-нибудь еще по этому поводу? Есть специальный раздел «Хуки: ответы на вопросы». Там мы находим следующее.
«React следит за тем, какой компонент рендерится в данный момент.… Существует внутренний список ячеек памяти, связанных с каждым компонентом. Они являются JavaScript-объектами, в которых мы можем хранить некоторые данные. Когда вызывается некий хук, например useState(), он читает значение текущей ячейки (или инициализирует её во время первого рендера) и двигает указатель на следующую. Таким способом каждый вызов useState() получит своё независимое состояние.»
Уже кое-что. Внутренний список ячеек памяти, связанных с компонентами и содержащих некоторые данные. Хук читает значение текущей ячейки и двигает указатель на следующую. Какую структуру данных вам это напоминает? Возможно, речь идет о связанном (связном) списке.
Если это и в самом деле так, то последовательность хуков, формируемая React при первом рендеринге, выглядит следующим образом (представим, что прямоугольники — это хуки, каждый хук содержит указатель на следующий):
Отлично, у нас есть рабочая гипотеза, которая выглядит более-менее разумно. Как нам ее проверить? Гипотеза гипотезой, но хочется фактов. А за фактами придется идти на GitHub, в репозиторий с исходниками React.
Не думайте, что я сразу решился на такой отчаянный шаг. Разумеется, сначала в поисках ответов на интересующие меня вопросы я обратился к всеведущему Гуглу. Вот что удалось обнаружить:
Реализация useState() и других хуков находится в ReactHooks.js:
Для вызова useState() (и других хуков) используется некий диспетчер. В начале того же файла видим следующее:
Диспетчер, который используется для вызова useState() (и других хуков), является значением свойства «current» объекта «ReactCurrentDispatcher», который импортируется из ReactCurrentDispatcher.js:
ReactCurrentDispatcher — это пустой объект со свойством «current». Значит, инициализируется он где-то в другом месте. Но где именно? Подсказка: импорт типа «Dispatcher» указывает на то, что текущий диспетчер как-то связан с «внутренностями» React. И действительно, вот что мы находим в ReactFiberHooks.new.js (число в комментарии — это номер строки):
Однако в ReactSharedInternals.js мы упираемся в «секретные внутренние данные, за использование которых можно быть уволенным»:
И что, это все? Неужели наши поиски, не успев начаться, подошли к концу? Не совсем. Деталей внутренней реализации React мы не узнаем, но нам это и не нужно для понимания того, как React управляет хуками. Возвращаемся в ReactFiberHooks.new.js:
В качестве диспетчера, который используется для вызова хуков, фактически используются два разных диспетчера — HooksDispatcherOnMount (при монтировании) и HooksDispatcherOnUpdate (при обновлении, повторном рендеринге).
Разделение «монтирование/обновление» сохраняется на уровне хуков.
Для обновления состояния используется функция «updateReducer», поэтому мы говорим, что useState внутренне использует useReducer или что useReducer — более низкоуровневая реализация useState.
Пока что мы увидели только, как работают сами хуки. Где же список? Подсказка: хуки при монтировании/обновлении создаются с помощью функций «mountWorkInProgressHook» и «updateWorkInProgressHook», соответственно.
Полагаю, наша гипотеза о том, что для управления хуками используется связный список, нашла свое подтверждение. Мы выяснили, что каждый хук имеет свойство «next», значением которого является ссылка на следующий хук. Вот хорошая иллюстрация этого списка из указанной выше статьи:
Для тех, кому интересно, вот как выглядит простейшая реализация однонаправленного связного списка на JavaScript:
Получается, что при повторном рендеринге с меньшим (или большим) количеством хуков, updateWorkInProgressHook() возвращает хук, не соответствующий своей позиции в предыдущем списке, т.е. в новом списке будет недоставать узла (или появится дополнительный узел). И в дальнейшем для вычисления нового состояния будет использовано неправильное мемоизированное состояние. Безусловно, это серьезная проблема, но насколько она критична? Неужели React не умеет перестраивать список хуков на лету? И существует ли какой-то способ реализовать условное использование хуков? Давайте это выясним.
Да, пока мы не ушли из исходников, поищем линтер, обеспечивающий соблюдение правил использования хуков. RulesOfHooks.js:
Не будет вдаваться в подробности того, как определяется разница между количеством хуков. А вот как определяется, что функция — это хук:
Набросаем компонент, в котором имеет место условное использование хуков, и посмотрим, что произойдет при его рендеринге.
В приведенном примере у нас имеется два пользовательских хука — useText() и useCount(). Мы пытаемся использовать тот или иной хук в зависимости от состояния переменной «active». Рендерим. Получаем ошибку «React Hook ‘useText’ is called conditionally. React Hooks must be called in the exact same order in every component render», которая говорит о том, что хуки должны вызываться в одинаковом порядке при каждом рендеринге.
Может быть, дело не столько в React, сколько в ESLint. Попробуем его отключить. Для этого добавляем /* eslint-disable */ в начале файла. Теперь компонент «Content» рендерится, но переключение между хуками не работает. Значит, дело все-таки в React. Что еще можно сделать?
Что если сделать пользовательские хуки обычными функциями? Пробуем:
Результат такой же. Компонент рендерится с getCount(), но переключиться между функциями не получается. К слову, без /* eslint-disable */ мы получим ошибку «React Hook „useState“ is called in function „getText“ that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter», которая говорит о том, что хук вызывается внутри функции, которая не является ни компонентом, ни пользовательским хуком. В этой ошибке кроется подсказка.
Что если сделать наши функции компонентами?
Теперь все работает, как ожидается, причем, даже с включенным линтером. Это объясняется тем, что мы фактически реализовали условный рендеринг компонентов. Очевидно, для реализации условного рендеринга компонентов React использует другой механизм. Почему этот механизм нельзя было применить в отношении хуков?
Проведем еще один эксперимент. Мы знаем, что в случае с рендерингом списка элементов, каждому элементу добавляется атрибут «key», позволяющий React отслеживать состояние списка. Что если использовать этот атрибут в нашем примере?
С линтером получаем ошибку. Без линтера… все работает! Но почему? Возможно, React считает Content с useText() и Content с useCount() двумя разными компонентами и выполняет условный рендеринг компонентов в зависимости от состояния active. Как бы то ни было, мы нашли обходной путь. Другой пример:
В приведенном примере у нас имеется пользовательский хук «useNum», каждую секунду возвращающий случайное целое число в диапазоне от 100 до 1000. Мы заворачиваем его в компонент «NumWrapper», который ничего не возвращает (точнее, возвращает null), но… за счет использования setNum из родительского компонента происходит подъем состояния. Конечно, фактически мы снова реализовали условный рендеринг компонента. Тем не менее, это показывает, что, при желании, добиться условного использования хуков все-таки можно.
Код примеров находится здесь.
Подведем итоги. Для управления хуками React использует связный список. Каждый (текущий) хук содержит указатель на следующий хук или null (в свойстве «next»). Вот почему важно соблюдать порядок вызова хуков при каждом рендеринге.
Несмотря на то, что добиться условного использования хуков через условный рендеринг компонентов можно, делать этого не следует: последствия могут быть непредсказуемыми.
Еще парочка наблюдений, связанных с исходниками React: классы практически не используются, а функции и их композиции являются максимально простыми (даже тернарный оператор используется редко); названия функций и переменных являются довольно информативными, хотя из-за большого количества переменных возникает необходимость использования префиксов «base», «current» и т.д., что приводит к некоторой путанице, но, учитывая размер кодовой базы, такая ситуация является вполне закономерной; присутствуют развернутые комментарии, включая TODO.
На правах саморекламы: для тех, кто хочет изучить или получше разобраться в инструментах, используемых при разработке современных веб-приложений (React, Express, Mongoose, GraphQL и т.д.), предлагаю взглянуть на этот репозиторий.
Надеюсь, вам было интересно. Конструктивные замечания в комментариях приветствуются. Благодарю за внимание и хорошего дня.
Справочник API хуков
Хуки — нововведение в React 16.8, которое позволяет использовать состояние и другие возможности React без написания классов.
На этой странице описан API, относящийся к встроенным хукам React.
Если вы новичок в хуках, вы можете сначала ознакомиться с общим обзором. Вы также можете найти полезную информацию в главе «Хуки: ответы на вопросы».
Возвращает значение с состоянием и функцию для его обновления.
Во время первоначального рендеринга возвращаемое состояние ( state ) совпадает со значением, переданным в качестве первого аргумента ( initialState ).
Функция setState используется для обновления состояния. Она принимает новое значение состояния и ставит в очередь повторный рендер компонента.
Кнопки «+» и «-» используют функциональную форму, потому что обновлённое значение основано на предыдущем значении. Но кнопка «Сбросить» использует обычную форму, потому что она всегда устанавливает счётчик обратно в 0.
Если функция обновления возвращает абсолютно такой же результат как и текущее состояние, то последующие повторные рендеры будут полностью пропущены.
Ленивая инициализация состояния
Аргумент initialState — это состояние, используемое во время начального рендеринга. В последующих рендерах это не учитывается. Если начальное состояние является результатом дорогостоящих вычислений, вы можете вместо этого предоставить функцию, которая будет выполняться только при начальном рендеринге:
Досрочное прекращение обновления состояния
Принимает функцию, которая содержит императивный код, возможно, с эффектами.
Мутации, подписки, таймеры, логирование и другие побочные эффекты не допускаются внутри основного тела функционального компонента (называемого этапом рендеринга React). Это приведёт к запутанным ошибкам и несоответствиям в пользовательском интерфейсе.
По умолчанию эффекты запускаются после каждого завершённого рендеринга, но вы можете решить запускать их только при изменении определённых значений.
Функция очистки запускается до удаления компонента из пользовательского интерфейса, чтобы предотвратить утечки памяти. Кроме того, если компонент рендерится несколько раз (как обычно происходит), предыдущий эффект очищается перед выполнением следующего эффекта. В нашем примере это означает, что новая подписка создаётся при каждом обновлении. Чтобы избежать воздействия на каждое обновление, обратитесь к следующему разделу.
Порядок срабатывания эффектов
Хотя useEffect откладывается до тех пор, пока браузер не выполнит отрисовку, он гарантированно срабатывает перед любыми новыми рендерами. React всегда полностью применяет эффекты предыдущего рендера перед началом нового обновления.
Условное срабатывание эффекта
По умолчанию эффекты запускаются после каждого завершённого рендера. Таким образом, эффект всегда пересоздаётся, если значение какой-то из зависимости изменилось.
Если вы хотите использовать эту оптимизацию, обратите внимание на то, чтобы массив включал в себя все значения из области видимости компонента (такие как пропсы и состояние), которые могут изменяться с течением времени, и которые будут использоваться эффектом. В противном случае, ваш код будет ссылаться на устаревшее значение из предыдущих рендеров. Отдельные страницы документации рассказывают о том, как поступить с функциями и что делать с часто изменяющимися массивами.
Если вы хотите запустить эффект и сбросить его только один раз (при монтировании и размонтировании), вы можете передать пустой массив ( [] ) вторым аргументом. React посчитает, что ваш эффект не зависит от каких-либо значений из пропсов или состояния и поэтому не будет выполнять повторных запусков эффекта. Это не обрабатывается как особый случай — он напрямую следует из логики работы входных массивов.
Массив зависимостей не передаётся в качестве аргументов функции эффекта. Тем не менее, в теории вот что происходит: каждое значение, на которое ссылается функция эффекта, должно также появиться в массиве зависимостей. В будущем достаточно продвинутый компилятор сможет создать этот массив автоматически.
Принимает объект контекста (значение, возвращённое из React.createContext ) и возвращает текущее значение контекста для этого контекста. Текущее значение контекста определяется пропом value ближайшего над вызывающим компонентом в дереве.
Запомните, аргументом для useContext должен быть непосредственно сам объект контекста:
useContext(MyContext) позволяет только читать контекст и подписываться на его изменения. Вам всё ещё нужен выше в дереве, чтобы предоставить значение для этого контекста.
Соединим все вместе с Context.Provider
Это пример из раздела Продвинутые темы: Контекст, только переписанный с использованием хуков. В этом же разделе можно найти больше информации о том, как и когда использовать объект Context.
Следующие хуки являются вариантами базовых из предыдущего раздела или необходимы только для конкретных крайних случаев. Их не требуется основательно изучать заранее.
Указание начального состояния
Это позволяет извлечь логику для расчёта начального состояния за пределы редюсера. Это также удобно для сброса состояния позже в ответ на действие:
Досрочное прекращение dispatch
Если вы вернёте то же значение из редюсера хука, что и текущее состояние, React выйдет без перерисовки дочерних элементов или запуска эффектов. (React использует алгоритм сравнения Object.is.)
Передайте встроенный колбэк и массив зависимостей. Хук useCallback вернёт мемоизированную версию колбэка, который изменяется только, если изменяются значения одной из зависимостей. Это полезно при передаче колбэков оптимизированным дочерним компонентам, которые полагаются на равенство ссылок для предотвращения ненужных рендеров (например, shouldComponentUpdate ).
Массив зависимостей не передаётся в качестве аргументов для колбэка. Концептуально, однако, это то, что они представляют: каждое значение, использованное в колбэке, должно также появиться в массиве зависимостей. В будущем достаточно продвинутый компилятор может создать этот массив автоматически.
Передайте «создающую» функцию и массив зависимостей. useMemo будет повторно вычислять мемоизированное значение только тогда, когда значение какой-либо из зависимостей изменилось. Эта оптимизация помогает избежать дорогостоящих вычислений при каждом рендере.
Если массив не был передан, новое значение будет вычисляться при каждом рендере.
Массив зависимостей не передаётся в качестве аргументов функции. Концептуально, однако, это то, что они представляют: каждое значение, на которое ссылается функция, должно также появиться в массиве зависимостей. В будущем достаточно продвинутый компилятор может создать этот массив автоматически.
Обычный случай использования — это доступ к потомку в императивном стиле:
Возможно, вы знакомы с рефами в основном как со способом получить доступ к DOM. Если вы передадите React объект рефа с помощью подобного выражения
Но хук useRef() полезен не только установкой атрибута с рефом. Он удобен для сохранения любого мутируемого значения, по аналогии с тем, как вы используете поля экземпляра в классах.
useDebugValue может использоваться для отображения метки для пользовательских хуков в React DevTools.
Мы не рекомендуем добавлять значения отладки в каждый пользовательский хук. Это наиболее ценно для пользовательских хуков, которые являются частью общих библиотек.
Отложите форматирование значений отладки
В некоторых случаях форматирование значения для отображения может быть дорогой операцией. Это также не нужно, если хук не проверен.
По этой причине useDebugValue принимает функцию форматирования в качестве необязательного второго параметра. Эта функция вызывается только при проверке хуков. Она получает значение отладки в качестве параметра и должна возвращать форматированное отображаемое значение.