Найти в Дзене
jsbook.ru

React Hooks: кастомные хуки

Сегодня мы с вами поговорим о кастоных хуках, что это такое и зачем это нужно. Начиная с React 16.8 всем разработчикам стали доступны хуки, на самом деле их можно было использовать и ранее но с этим было связанно ряд проблем. React Hooks упрощают процесс написания чистого, читаемого и переиспользуемого кода, и такие продвинутые техники как мемоизация стали более доступными и простыми в использовании. В официальной документация React кастомные хуки описаны не так подробно как базовые хуки, поэтому в этой статье мы попробуем устранить этот недочет, также мы поговорим о best practice в конексте хуков. Для лучшего восприятия этой статьи вам необходимы знания о базовых хуках в реакт. Если вы незнакомы с базовыми хуками существует множество отличных статей их описывающие. Например вот отличная статья о хуках. Небольшое отступление Чтобы создавать универсальные, производительные и переиспользуемые кастомные хуки, необходимо помнить о нескольких вещах. Хуки вызываются при каждой перерисовке ко
Оглавление

Сегодня мы с вами поговорим о кастоных хуках, что это такое и зачем это нужно.

Начиная с React 16.8 всем разработчикам стали доступны хуки, на самом деле их можно было использовать и ранее но с этим было связанно ряд проблем.

React Hooks упрощают процесс написания чистого, читаемого и переиспользуемого кода, и такие продвинутые техники как мемоизация стали более доступными и простыми в использовании.

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

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

Небольшое отступление

Чтобы создавать универсальные, производительные и переиспользуемые кастомные хуки, необходимо помнить о нескольких вещах.

Хуки вызываются при каждой перерисовке компонента

Так как мы работаем с функциональными компонентами и хуками, нам больше ненужно работать с класическими методами жизненого цикла компонента ( Lifecycles ). Каждый раз когда мы изменяем props или state функциональный компонент перерисовывается, и, таким образом, наш кастомный хук вызывается снова и снова.

Правила использования хуков

Есть несколько важных правил о которых нужно постоянно помнить при работе с хуками. Эти правила подробно описаны в этой статье.

Постановка задачи

Теперь, после того как мы поговорили об основах, мы готовы приступить к созданию нашего первого кастомного хука. В следующем примере мы реализует наш хук используя для этого best practices и solid pattern.

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

Учитывая это мы, мы создадим хук useGameDice который будет обладать следующим функционалом:

  • при инициализации можно передать число ( значение на грани кубика ) которое будет использоватся как начально значение;
  • устанавливает количество используемых кубиков;
  • возвращает массив случайных чисел от 1 до 6. Длина определяется количеством используемых кубиков;
  • в качестве начального значения всех кубиков устанавливается передаваемое значение;

Создание хука

В качестве основы для хука мы будем использовать стрелочную функцию, как упоминалось ранее хук будет называтся useGameDice, здесь мы используем рекомендуемое соглашение именования пользовательских хуков ( имя должно начинаться с ключевого слова «use»).

Для реализации нашего функционала мы будем использовать предустановленые в React хуки. Также мы можем использовать другие кастомные хуки, библиотеки и все что угодно, что нам нужно для работы.

При создании хука в него можно передать 2 аргумента:

  • initialNumberOfDice - количество костей;
  • initialDiceValue - используется в качестве начального значения и значение после сброса;

для того что бы у нас не возникало ошибок в качестве значения по умолчанию мы установим 1:

Добавим состояние и кеширование

Для начала мы настроим наш state, для этого добавим 2 хука для работы с состоянием:

  • diceValue - массив, размер которого задается с помощью numberOfDice и содержит значение для каждого кубика
  • numberOfDice - определяет количество кубиков (размер массива diceValue), которые будут использоваться

Мы также инициализируем переменную initialDiceState, которая задает начальное значение массива, которое устанавливается при первом рендеринге и сбросе состояния. Это значение запоминается, чтобы избежать инициализации массива и заполнения значениями по умолчанию при каждом повторном рендеринге.

-2

Добавляем кеширование

Для этого добавим в наш код следующие функции:

  • generateRandomDiceNumber - генерирует случайное значение от 1 до 6 ( один бросок кости );
  • rollDice - генерирует случайное значение для каждого элемента в массиве;
  • resetDice - сбрасывает значение кубика до начального;
-3

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

Добавляем сайд эффект - инициализация и обновление хука

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

  • устанавливает начально значение кубика при первой инициализации хука;
  • обновляет значение кубика до начального когда изменяет количество кубиков ( размер массива );
-4

Настройка API и возвращемое значение

Наконец, мы определяем наши объекты состояния и API и возвращаем их в массиве в соответствии с соглашением об использовании состояния. Давайте рассмотрим каждый объект:

  • state - содержит все данные с которыми нам предстоит работать, будет изменятся в большинстве случаев при повторной отрисовке;
  • api - содержит все функции. Мы возвращаем некоторые из наших функций, объявленных в useCallback, и функцию из хука useState. Этот объект кэшируется, так как ожидается что изменения будут затрагивать его нечасто;
-5

Мы возвращаем объекты в массиве, потому что хотим, чтобы этот хук был гибким. Тем самым мы позволяем разработчикам переименовывать возвращаемые переменные и при необходимости инициализировать несколько экземпляров этого хука.

-6

В конечном итоге наш хук будет выглядеть так:

-7

Обзор паттерна React custom hook

На данный момент мы сгрупировали наш код в единую сущность. Этот подход позволяет структурировать наш код и сохранять его чистым как можно дольше. В кастомных хуках мы можем работать с :

  • инициализация состояния (useState, useReducer), инициализация локальных переменных (useMemo), инициализация ref (useRef) и инициализация внешних пользовательских хуков;
  • функции кэширования (useCallback);
  • Побочные эффекты (useEffect);
  • работа с API;

Заключение

Не удивительно, что хуки были хорошо приняты сообществом React. Разработчики могут легче обмениваться логикой между компонентами, создавать несколько компонентов (интерфейсов) для каждого кастомного хука и т. д.

Хуки позволяют нам писать чистый, оптимизированный и многократно преиспользуемый код.

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

https://dev.to/prototyp/building-custom-react-hooks-11h2