Перехватчики React позволяют использовать состояние и другие функции React без написания класса.

Если вы новичок в сообществе React или имеете хороший опыт, то наверняка слышали о React Hooks. Очень полезный способ встраивать логику с отслеживанием состояния в функциональный компонент без необходимости превращать его в компонент класса. Это также означает, что мы можем легко обмениваться состоянием между компонентами без необходимости в компоненте более высокого порядка.

В этом примере я хотел использовать что-то, немного отличное от состояния React, но вместо этого состояние из URL-адреса для чтения и обновления параметров поиска. Я обнаружил, что этот крючок действительно полезен для получения параметра поиска, который может быть установлен из компонента SearchBox, но считан из компонента List, например.

Мы расскажем, как настроить новый пользовательский React Hook, определив наш API и логику в нашем Hook. В следующей статье я расскажу, как мы можем затем протестировать это с помощью библиотеки Jest и React Testing Library.

Первый шаг - определение функциональности и контракта хука.

Я большой поклонник маленьких простых хуков, которые легко понять, что они делают. Если у них есть только одна обязанность, они более гибкие и могут часто использоваться повторно. Здесь мы берем UrlSearchParams API и превращаем его в ловушку, чтобы мы могли легко устанавливать, удалять и обновлять значения параметров URL в компоненте.

Если вы знакомы с API URLSearchParams, вы знаете, что вам нужно определить ключ при манипулировании параметрами. Здесь мы можем передать это, когда настроим крючок, чтобы он был определен один раз.

Итак, наш контракт остается простым:

parameterName => ({ setValue, getValue })

Организация хуков в вашем проекте

Файловые структуры различаются, но я думаю, мы все согласны с тем, что хуки должны храниться вместе, поскольку они являются общими. Так что давайте предоставим им их собственный каталог вне базы вашего проекта или src папку.

В качестве примера я могу использовать следующую структуру:

src
 - components
 - pages
 - hooks

Теперь мы разместили наш Hook, давайте создадим новый файл для определения нашего Hook. Лучше всего создавать хуки, начинающиеся с use so, что должно быть знакомо по встроенным в React хукам useState, useCallback и useEffect. Мне очень нравится useSearchParams.js, поэтому я буду использовать его здесь, но мы также могли бы пойти с useUrlSearchParams.js, чтобы быть более точным.

Запуск объекта URLSearchParams

Чтобы запустить наш Hook, нам нужно создать новый экземпляр свойства UrlSearchParam с нашим именем параметра. Это будет первая работа Крюка, так что отличное место для начала.

const useSearchParams = parameterName => {
  const location = useLocation();
  const history = useHistory(); 
  const urlParams = new URLSearchParams(location.search)
}

Создайте метод getValue

Легко, здесь мы можем просто повторно использовать то, что предоставляет API, но взять наш параметр «parameterName», установленный при определении хука. Больше нам здесь нечего взлетать.

{
  getValue: () => urlParams.get(parameterName)
}

Теперь о методе setValue

Немного сложнее, чем получить, нам нужно рассмотреть несколько разных сценариев здесь:

  1. Есть набор значений, мы хотим его удалить.
  2. Есть набор значений, и нам нужно заменить это
  3. Значение еще не установлено

Каждый из них обрабатывается отдельно в API URLSearchParams, но мы можем комбинировать логику, чтобы наш API оставался чистым и простым.

Для нашего первого варианта использования мы можем использовать метод delete, предоставляемый API URLSearchParams. Это просто удалит любое установленное значение, если мы передадим пустое значение val в качестве значения обновления.

Второй и третий сценарии нуждаются в подробностях. В нашем примере мы хотим иметь возможность перезаписать любое значение тем, которое мы передали нашему методу set. Для этого в URLSearchParams есть встроенный set метод, который удаляет все предыдущие значения и устанавливает новое, отлично! В нашем последнем сценарии у нас нет значения, поэтому вместо этого мы можем просто append значение вместо выполнения дополнительных действий, чтобы сначала удалить значение.

Итак, давайте сложим все вместе, и мы взяли удар:

const setValue = (val = "") => {
  if (!val) {
    // #1  
    urlParams.delete(parameterName);
  } else if (urlParams.has(parameterName)) {
    // #2
    urlParams.set(parameterName, val);
  } else {
    // #3
    urlParams.append(parameterName, val);
  }
  return urlParams;
}

Чтобы узнать более подробно обо всех методах API URLSearchParam, я предпочитаю веб-сайт MDN.

Изменение URL-адреса с помощью наших новых параметров поиска

Теперь у нас есть наши set и get методы, мы можем просто оставить наш Hook как есть и предоставить потребляющему компоненту изменить URL-адрес, на который устанавливается / обновляется параметр поиска. Или мы могли бы добавить это в конец нашего setValue метода. Я думаю, что метод setValue был бы намного полезнее, если бы он позаботился об обновлении URL-адреса за нас, поэтому давайте добавим его сейчас.

const setValue =  (val = "") => {
  if (!val) {
    // #1  
    urlParams.delete(parameterName);
  } else if (urlParams.has(parameterName)) {
    // #2
    urlParams.set(parameterName, val);
  } else {
    // #3
    urlParams.append(parameterName, val);
  }
  history.replace({
    ...location, // <-- Pulled in from the useLocation Hook
    search: decodeURIComponent(urlParams.toString())
  });
  return urlParams;
}

Теперь у нас есть все части пазла, которые мы можем собрать вместе, чтобы создать наш первый крючок, который вы можете найти полностью здесь.

В заключение

Итак, у нас есть React Hook, который вместо использования состояния React мы берем состояние из URL-адреса, который имеет понятный и простой API. Отсюда мы могли бы делиться этим между множеством различных компонентов и синхронизировать состояние, не оборачивая их в Компонент более высокого порядка.

Следующий логический шаг - написать несколько тестов для этого, я расскажу об этом в следующей статье, в которой рассказывается, как мы настраиваем тесты Jest для Hook’s и используем вместе с ним библиотеку тестирования React.

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