Простое руководство по созданию пользовательских хуков в React

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

Если вы знаете об абстракции, это здорово, а иногда и нет. Тем не менее, иногда нам нужно нечто большее, чем простая абстракция, чтобы сделать код читаемым и пригодным для повторного использования. Используя нестандартные крючки, мы стремимся достичь преимуществ абстракции в сочетании с гибкостью и мощностью современных крючков. Прежде чем двигаться дальше, я рекомендую прочитать о встроенных хуках, таких как useState и useEffect, в документации React, если вы еще не знакомы.

3 шага к созданию собственного крючка

  1. организовать. Моя любимая практика - создать каталог хуков на верхнем уровне проекта, чтобы все пользовательские хуки было легко найти. Фактически, Visual Studio Code имеет значок по умолчанию, когда вы создаете папку с именем «хуки». По моим правилам, это хороший знак!
  2. name. Я предпочитаю начинать имена ловушек с «use», а затем не давать им расплывчатых имен, таких как «use», а затем представлять их ответственность вплоть до сути. Хорошим примером может быть что-то вроде «useToggle». Это совершенно очевидно!
  3. design hook! на самом деле очень просто создать настраиваемые хуки реакции! Просто будьте осторожны с тем, какая логика там размещена, и имейте в виду, если они требуют очистки. Отсутствие этой точки может привести к утечке памяти!

Давайте рассмотрим несколько примеров ниже!

Примеры простых кастомных крючков

Чаще всего мы основываем свои собственные хуки на уже существующих. Давайте начнем с создания суперпростого настраиваемого хука с именем useToggle, который использует useState в качестве основы.

Пример №1: useToggle - лучше всего подходит для режима включения / выключения

Давайте рассмотрим этот пример построчно (подождите, их всего 5):

  1. Сначала мы создаем функцию с именем useToggle, которая принимает логическое значение в качестве аргумента, который действует как initialState ловушки. Если ничего не указано, по умолчанию будет установлено значение false.
  2. Затем мы используем стандартное выражение, полученное из встроенного в React хука useState. Это то, что обычно будет использоваться для хранения и управления нашим переключателем. Это выражение предоставит нам доступ к state - логической переменной (в данном случае), которая будет сохраняться при рендеринге - и setState - методу, который при передаче логического значения запланирует обновление состояния и, соответственно, вызовет повторный рендеринг.
  3. Затем мы определяем локальный метод toggle, который считывает текущее состояние и устанавливает противоположное. Другими словами, если состояние истинно, оно установит его в ложное и наоборот.
  4. Наконец, из нашего хука возвращается массив, содержащий ссылку на наше переключаемое состояние ([0]) и на наш метод переключения ([1]). Вот и все. Внедрите его в свой компонент и сходите с ума! Чтобы узнать об оптимизированной версии этого простого крючка, обратитесь сюда.
  5. Ах да ... и вот это "}"

Мы можем использовать этот код, чтобы сделать что-то простое, но яркое, например следующий выключатель света (код ниже):

Пример # 2: useFocusToggle - для обработки, когда экран реакции-навигации сфокусирован или размыт

Чтобы представить сценарий, в котором это может быть полезно, представьте себе следующее: моя команда обнаружила такую ​​ошибку, что при попытке перейти на определенный экран приложение вылетало. Вскоре мы поняли, что этот сбой вызывает какой-то сложный компонент, работающий в фоновом режиме. После более глубокого исследования я узнал, что при использовании Bottom Tab Navigator в response-navigation экраны не отключаются после смены вкладок. Другими словами, одним из решений было найти способ отключить проблемный компонент, когда экран теряет фокус. Сначала я попытался использовать useFocusEffect в реакции-навигации, но после этого у меня не получилось - так как я продолжал сталкиваться с ошибкой и не было времени копать глубже - я построил следующий хук:

Этот настраиваемый обработчик с именем useFocusToggle принимает 1 обязательный и 2 необязательных аргумента.

  1. навигация (обязательно). Это должен быть какой-то тип NavigationProp, принадлежащий какому-либо экрану в проекте с использованием реакции-навигации.
  2. focusEvents (необязательно). Это должен быть обратный вызов, содержащий любые задачи, которые будут выполняться при фокусировке экрана.
  3. blurEvents (необязательно). Это должен быть обратный вызов, содержащий любые задачи, которые будут выполняться, когда экран покидает фокус.

Начиная со строки 2, ловушка устанавливает состояние, подобное переключателю, чтобы показать, сфокусирован ли экран, реализующий ловушку, или нет.

Затем мы используем 2 отдельных хука useEffect, которые будут выполняться каждый раз при обновлении ссылки навигации (опора №1). Учитывая поведение реакции-навигации, это обычно не происходит чаще, чем пару раз, в зависимости от архитектуры вашего приложения. В каждом хуке мы определяем разные, но похожие прослушиватели событий, используя метод navigation. AddEventListener response-navigation. Один слушатель изменит состояние на true и выполнит любые обратные вызовы, переданные в focusEvents (опора № 2), когда экран сфокусируется. А другой слушатель изменит состояние на false и выполнит любые обратные вызовы, переданные в blurEvents (опора № 3), когда экран покидает фокус.

Наконец, мы возвращаем состояние, показывающее, находится ли экран в фокусе или нет.

Я понимаю, что может возникнуть некоторая путаница в отношении полезности этого крючка, и в этом случае позвольте мне установить, что этот крючок действительно предназначен только для компонентов экрана верхнего уровня, использующих реагирующую навигацию. Если в любом случае useFocusToggle был вызван компонентом более низкого уровня, то ему нужно было бы передать свойство навигации одним из его родительских экранов.

Если вернуться к нашей исходной дилемме, даже если наш экран вкладок останется смонтированным, этот крючок позволяет нам монтировать и отключать дочерние компоненты, используя состояние сфокусировано. Это простой пример того, как это может выглядеть в действии:

Когда не использовать кастомные крючки (или крючки в целом)

Предположим, вы создаете экран оформления заказа для компании, и он должен иметь всевозможные побочные эффекты. Так, например, когда пользователь добавляет товар в корзину, он получит скидку 20% и бесплатную доставку, если потратит более 50 долларов (при условии, что бизнес только начинается и, вероятно, будет очень щедрым в надежде нарастить обороты). . Давайте посмотрим на несколько способов реализовать это:

Подход №1 с индивидуализированной обработкой:

Технически мы могли бы создать ненужный настраиваемый хук, который принимает 3 аргумента: опору для «отслеживания», условное выражение, которое ожидает опору как параметр и возвращает логическое значение, и начальное состояние. Давайте посмотрим, как это реализовано:

Каждый раз, когда свойство amountSpent изменяется, useEffect из нашего useConditionalHook будет срабатывать и сообщать, имеет ли пользователь право на скидку.

Подход № 2: без специальной ловушки

Вот почему вам НЕ нужна эта ловушка… useEffect и useState здесь использовать не нужно. Мы всегда должны помнить, что при изменении свойств наш компонент повторно отрисовывается. Таким образом, большинство выражений (не подключенных) читаются и выполняются еще раз. В заключение, все, что нам нужно, это выражение, подобное приведенному ниже, чтобы заменить наш хук в строке 4, чтобы добиться тех же результатов:

const eligibleForDiscount = amountSpent > 50

Вуаля! Каждый раз, когда родительский элемент изменяет amountSpent, параметр elhibitedForDiscount будет обновляться именно так, как нам нужно. Я думаю, что хороший способ избежать первого подхода - быть осторожным при использовании props для инициализации локального состояния.

Надеюсь, вы кое-что узнали из этой статьи! Перейдите по ссылкам здесь для дальнейшего чтения и свяжитесь со мной, если вы нашли эту статью интересной, у вас есть какие-либо вопросы или комментарии. Голосуйте за помощь и благодарим за вашу поддержку!

Больше контента на plainenglish.io