Шпаргалка по хукам в React.
Шпаргалка по хукам React: базовый уровень 1. Зачем в React нужны хуки?
Хуки подходят для решения следующих задач.
1. Повторное использование логики с отслеживанием состояния (stateful logic) без изменения иерархии компонентов. Хуки помогают извлечь такую логику из компонента, независимо протестировать и повторно использовать ее. Такие хуки можно использовать в разных компонентах, ими легко обмениваться с другими членами команды.
Требующи
Шпаргалка по хукам в React...
 
Шпаргалка по хукам React: базовый уровень
1. Зачем в React нужны хуки?
Хуки подходят для решения следующих задач.
1. Повторное использование логики с отслеживанием состояния (stateful logic) без изменения иерархии компонентов. Хуки помогают извлечь такую логику из компонента, независимо протестировать и повторно использовать ее. Такие хуки можно использовать в разных компонентах, ими легко обмениваться с другими членами команды.
Требующие реструктуризации компонентов паттерны  —  рендер-пропы и компоненты высшего порядка (HOC  —  Higher Order Components)  —  усложняют работу, затрудняя отслеживание кода. Хуки упрощают и эти задачи.
2. Разделение компонента на более мелкие функции. Хуки упрощают программирование методов жизненного цикла. Каждый из таких методов часто содержит набор несвязанной логики. Компоненты могут выполнять выборку данных с помощью componentDidMount(). В то же время этот метод может включать и некоторую несвязанную логику, настраивающую слушателей событий.

То же самое можно сделать со встроенными хуками React, такими как useState и useEffect:

Код становится проще и короче, что особенно ценно для команды разработчиков. Индивидуально обрабатываемые методы жизненного цикла, такие как componentDidMount(), componentDidUpdate() и componentWillUnmount(), может заменить один хук React useEffect().
3. Больше функций React без классов. До появления хуков в React использовались в основном компоненты на основе классов. Это требовало больших (а иногда и ненужных) усилий, потому что часто приходилось переключаться между классами, отображать пропы, HOC и т. д. Теперь благодаря хукам все это можно делать без переключений, используя функциональные компоненты.
- Использование компонентов на основе классов:

- Использование функциональных компонентов:

Если сравнивать оба эти варианта, второй подход с функциональным компонентом имеет значительно более простой код, а результаты одинаковые. Здесь не нужно выделять место для экземпляра класса, а затем вызывать функцию render(). Вместо этого просто вызывается функция.
2. Хук useState
 Хук
useStateпозволяет использовать в функциональном компоненте состояние локального приложения.
Он возвращает хранящее состояние значение (stateful) вместе с функцией своего обновления. Вот основная сигнатура вызова:

Используемая для обновления состояния функция setState принимает новое значение состояния (newState):

Имеется несколько важных особенностей при использовании useState.
1. Объявление переменной состояния. Чтобы объявить переменную состояния, нужно просто вызвать useState с некоторым начальным значением:

2. Обновление переменной состояния. В этом случае нужно вызвать функцию обновления, возвращаемую при вызове useState:

3. Использование переменных с разными состояниями. Их можно применять, обновляя внутри функционального компонента. Например:

4. Использование переменных состояния объекта. Весь объект можно использовать в качестве начального значения, передаваемого useState. При этом не будет автоматического слияния обновляемых объектов.

Новое состояние объекта: { name: "John", age: "unknown" }.
5. Функциональность useState. Возвращаемая после вызова useState функция обновления может быть подобна использованной в setState основанного на классе компонента:

Обе эти формы применимы для вызова updateValue.
3. Хук useEffect
 Хук
useEffectпринимает функцию для выполнения любых побочных эффектов.
Переданная в useEffect функция обычно будет запущена после завершения отработки на экране рендера. Но активировать эти эффекты можно и в зависимости от изменения определенных значений.
Сигнатура вызова useEffect:

Для создания базового побочного эффекта используем в следующем примере хуки useState и useEffect:

Блок useEffect обновляет заголовок текущей вкладки/окна браузера после выполнения функции handleClick.
Полезные особенности useEffect:
1. Очистка эффекта. Периодически нужно очищать effect, обычно это делают возвратом функции из переданной в useEffect функции эффекта (effectFunction).

Эта функция очистки выполняется для освобождения памяти перед удалением компонента из пользовательского интерфейса. К тому же создание нового кода очистки означает, что предыдущий эффект очищается перед выполнением следующего.
2. Создание нескольких эффектов. Добавить несколько эффектов позволяют несколько вызовов useEffect в одном функциональном компоненте. Пример:

3. Пропуск эффектов. Чтобы не вызывать хук при каждом рендере, можно пропускать вызовы useEffect. Сделать это можно разными способами:
- Использование массива зависимостей (dependency array). При этом в useEffect передается массив значений. Таким образом функция effect будет вызываться в процессе монтажа “and” при любой передаче сгенерированного нами значения. Например:

- Использование пустого массива зависимостей. В этом случае useEffect передает пустой массив []. Теперь функция эффекта вызывается только при монтаже:

- Отсутствие массива зависимостей. Можно полностью пропустить эффекты, вообще не предоставляя массив зависимостей. Функция эффекта будет выполняться после каждого рендера:

4. Правила использования хуков
Для эффективного использования хуков React следует соблюдать два основных правила.
- Вызывайте хуки на верхнем уровне. Другими словами: не вызывайте их внутри циклов, условий или вложенных функций.
Гарантированный таким образом вызов хуков каждый раз будет происходить в одном и том же порядке при рендере компонента. Это поможет сохранить состояние приложения между несколькими вызовами useState и useEffect.
Поэтому перед любыми ранними возвратами всегда следует контролировать использование хуков на верхнем уровне функции. React учитывает порядок вызова хуков, поэтому их вызов каждый раз в одном и том же порядке будет выглядеть следующим образом:

Но если поместить вызов хука persistForm внутрь условия:

Тогда, используя хук внутри условия, нарушается первое правило! Теперь порядок изменится следующим образом:

React не знает, что возвращать при втором вызове useState. Поэтому несколько пропущенных хуков вызвали проблемы.
2. Вызывайте хуки только из функций React. Другими словами: не вызывайте хуки из обычных функций JavaScript.
Следуя этому правилу, мы гарантируем хорошую наглядность кода логики с состоянием компонента.
Вместо того вызова хуков из обычных функций, можно:
- вызывать хуки из компонентов функций React;
- вызывать хуки из пользовательских хуков.
Шпаргалка по хукам React: средний уровень
1. Создание пользовательских хуков
При необходимости и в дополнение к имеющимся useState и useEffect можно создавать и собственные хуки для извлечения логики компонента в повторно используемых функциях.
Пользовательские хуки — это тип функций с префиксом “use”, которые могут вызывать другие функции.
При этом не обязательно иметь конкретную сигнатуру. Вот что следует учитывать при создании пользовательского хука.
- Извлечение пользовательского хука. Пользовательские хуки используются для совместного использования логики между двумя функциями JavaScript с последующим ее извлечением в третью функцию. При этом следует убедиться в безусловном вызове других хуков только на верхнем уровне пользовательского хука. Например:

Здесь useFriendStatus использует хуки useState и useEffect для взаимодействия с фрагментом кода для подписки на статус друга.
2. Использование пользовательских хуков. После создания их можно использовать в любой части компонентов. Например, есть пользовательский хук под названием useBoolean, возвращающий состояние и функции для обновления состояния массива:

Следует отметить, что initialState передается в качестве аргумента вместе с его значением по умолчанию (false). Вернувшись в компонент App, этот хук можно использовать, передавая ему начальное состояние и используя возвращаемые значения для отображения и обновления состояния. Например:

2. Хук useContext
 Устранить зависимость разработчика от потребителя контекста позволяет хук useContext.
Он принимает паттерн контекстного объекта (context object) и возвращает текущее значение этого контекста.
Контекстный объект берется из React.createContext и определяется пропом value, ближайшего (выше вызывающего компонента в дереве) <MyContext.Provider>. Вот сигнатура вызова:

Context в React инициализируется с помощью API верхнего уровня createContext. Пример:

Функция createContext принимает начальное значение по умолчанию, если не определен проп value. Можно использовать ее в примере компонента Book:

Хук useState принимает Context в качестве параметра, чтобы извлечь из него value. Теперь вышеупомянутый компонент Book из useContext получится таким:

3. Хук useReducer
 Хук
useReducer— альтернативаuseState. Обычно его используют для сложной логики состояния, включающей несколько уровней значений или при зависимости текущего состояние от предыдущего.
Сигнатура вызова:

Он принимает редуктор типа (state, action) => newState и возвращает текущее состояние в паре с методом dispatch. Пример использования этого хука:

Инициализировать состояние можно передачей функции init в качестве третьего аргумента. Возвратом из этой функции будет объект state. Пример для иллюстрации:

4. Хук useCallback
 Хук
useCallbackиспользуется для возврата мемоизированной версии переданного обратного вызова (callback), который меняется только в случае изменения одной из зависимостей.
Его удобно использовать при передаче обратных вызовов оптимизированным дочерним компонентам, чтобы избежать ненужного рендера. Сигнатура вызова:

Использовать useCallback со встроенной функцией можно при вызове следующим образом:

Здесь дочерний компонент <Instructions /> имеет проп doSomething, который передается при вызове хука useCallback.
5. Хук useMemo
 Хук
useMemoпозволяет мемоизировать сложные функции, чтобы не вызывать их при каждом рендере.
После передачи функции “create” и массива зависимостей получим мемоизированное значение. Сигнатура вызова этого хука:

При использовании хука useMemo следует учитывать следующие особенности:
- Мемоизированное значение будет пересчитано только в случае изменения одной из переданных зависимостей.
- В этот вызов нельзя добавлять побочные эффекты  —  они должны принадлежать хуку useEffect.
- В процессе начального рендеринга useMemoвызываетcompute, мемоизирует результат и возвращается в свой компонент.
- Если не предоставлять массив, новое значение будет вычисляться при каждом рендере компонента, в котором используется useMemo.
Допустим, имеется компонент <CalculateFactorial />:

Можно мемоизировать вычисление факториала при каждом повторном рендере компонента с помощью useMemo(() => factorialOf(number), [number]), как показано ниже в обновленном коде:

6. Хук useRef
 Хук
useRefвозвращает мутабельный объектrefсо свойством.current, которое инициализировано переданным аргументом(initialValue).
Он имеет следующую сигнатуру вызова:

Следует учитывать очень важные особенности useRef:
- useRefдействует как “ящик”, способный хранить изменяемое значение в своем свойстве- .current.
- Этот хук создает обычный объект JavaScript. Разница между useRef()и созданием объекта{ current: … }заключается в том, чтоuseRefдает один и тот же объектrefпри каждом рендере.
- Если изменить свойство .current, это не вызовет повторного рендера. Хук не уведомляет об изменении своего содержимого.
- Значение ссылки сохраняется, т. е. остается неизменным при повторном рендере компонента.
- Ссылки также могут обращаться к элементам DOM. Для этого нужно обратиться к атрибуту refэлемента, к которому нужен доступ.
Вот пример, в котором нужно получить доступ к элементу DOM, чтобы сфокусироваться на поле ввода при монтировании компонента:

Ссылка на элемент ввода в inputRef присваивается после создания атрибуту ref поля ввода. После монтирования React устанавливает inputRef.current в качестве элемента ввода.
Шпаргалка по хукам React: продвинутый уровень
1. Тестирование хуков React
Если не нужно тестировать внутренние компоненты React, то тестирование компонентов с хуками ничем не отличается от обычного.
Предположим, имеется компонент для подсчета нажатий на кнопку:

Сократить шаблонный код позволяет тестирование с помощью React DOM или библиотеки React Testing Library. Но давайте посмотрим, как это сделать с помощью базового кода. Чтобы убедиться в соответствии поведения происходящему в браузере, обернем рендеринг кода и обновление в несколько вызовов ReactTestUtils.act():

2. Получение данных с помощью хуков React
Получение данных  —  довольно типичный паттерн при работе с приложениями React. Но как получать данные с помощью хуков в конкретном компоненте приложения.
Допустим имеется базовый компонент App, который показывает список элементов:

И состояние, и функция обновления состояния приходят из хука useState. Для получения данных воспользуемся библиотекой Axios. Реализуем эффект хука:

Но запустив приложение вы увидите, что код крутится в цикле. Эффект хука запускается и при монтировании, и при обновлении компонента. Мы устанавливаем состояние после каждой выборки данных. Чтобы исправить это, необходимо получать данные только при монтировании компонента. Поэтому нужно предоставить пустой массив в качестве второго аргумента хука useEffect:

Дополнительно улучшить качество кода можно с помощью асинхронной функции внутри useEffect, возвращающей функцию очистки в Promise. Финальный код будет выглядеть так:

3. Создание с помощью хуков индикатора загрузки
Базовый индикатор загрузки реализуем на основе использованного выше примера загрузки данных. Для этого добавим еще одно значение состояния с помощью хука useState:

Внутри вызова useEffect можно установить переключатель значений true и false для setIsLoading:

При вызове эффекта для получения данных, когда компонент монтируется или изменяется состояние URL, состояние загрузки устанавливается в true:

4. Прерывание выборки данных с помощью хуков
Часто установленное состояние имеется даже у смонтированного компонента. Чтобы не столкнуться в этом случае с ошибками или циклами, нужно прервать получение данных в компоненте.
Можно использовать эффект хука с функцией очистки, запускаемый при размонтировании компонента. Воспользуемся этим вариантом для предотвращения выборки данных:

Мы использовали булевое значение didCancel, чтобы код извлечения данных знал о состоянии компонента (смонтирован/ размонтирован). Если оно размонтировано, флаг устанавливается в true, что предотвращает установку состояния компонента после разрешения асинхронной выборки данных.
5. Получение предыдущих пропов или состояний с хуками
Для очистки используемого эффекта иногда нужны предыдущие пропы компонента. Для иллюстрации представим эффект с подпиской на сокет на основе пропа userId. Если он меняется, мы хотим отписаться от ранее установленного userId, а затем подписаться на другой. Для этого можно использовать функцию очистки с функцией useEffect:

Сначала будет запущен ChatAPI.unsubscribeFromSocket(3), а затем  —  ChatAPI.unsubscribeFromSocket(4) (в порядке очереди при изменении userId). Таким образом, функция очистки делает всю работу за нас и закрывает предыдущий userId .
Заключение
В этой шпаргалке по хукам React рассмотрены и проиллюстрированы соответствующими примерами все главные особенности работы с хуками — начиная с их назначения и заканчивая дополнительными возможностями эффективного управления состоянием приложения.
 
                                 
 