Я большой фанат новых API хуков. Но знаете, у них есть странные ограничения по применению. Для тех, кто жаждет понять причины появления этих правил, здесь я представлю модель понимания, того, как их применять.
Предупреждаю: Хуки сейчас в статусе эксперимента
Эта статья об API хуков, который на данный момент находится в тестовом режиме. Документацию по стабильной версии React API можно найти здесь.
Как работают хуки?
Я слышал о борьбе некоторых людей с предложенным проектом API хуков. Поэтому здесь я попытаюсь разъяснить, как работает предложенный синтаксис, по крайней мере, поверхностно.
Правила хуков
Есть два основных правила, упоминаемые командой React, которым вы должны следовать, используя хуки. Они описаны в документации.
- Не вызывайте хуки внутри циклов, условий или вложенных функций
- Вызывайте хуки только из функций React
Последнее, я думаю, очевидно. Чтобы назначить поведение функциональному компоненту, нужно иметь возможность как-то ассоциировать это поведение с этим компонентом.
А вот первый пункт может сбить с толку. Это кажется не естественным, для программ, использующих подобные API и именно об этом я и хочу поговорить.
Управление состояниями в хуках — всё дело в массивах
Чтобы внести ясность в эту модель понимания, давайте посмотрим на простейшую реализацию API хуков.
Пожалуйста имейте в виду, что это всего лишь рассуждения и один из возможных способов реализации API, чтобы показать вам, как можно относиться к хукам. Речь пойдёт не о внутреннем устройстве API. Более того, это не окончательная реализация хуков, в будущем всё может измениться.
Как можно реализовать `useState()` ?
Давайте разберём пример, чтобы продемонстрировать реализацию state hook.
Начнём с компонента:
Идея API хуков в том, что вы можете использовать сеттер-функцию, возвращённую в качестве второго элемента массива из хуки-функции. Этот сеттер будет контролировать state, под управлением хуков.
Итак, что же React будет с этим делать?
Давайте разберёмся, как это будет работать внутри React. Этот код будет работать в контексте исполнения, для отображения определённого компонента. Это значит, что данные, которые здесь хранятся, «живут» за пределами этого компонента. Этот state не доступен другим компонентам, но поддерживается в пространстве, которое доступно для дальнейшего рендеринга определённого компонента.
1) Инициализация
Создаём два пустых массива: `setters` и `state`
Устанавливаем курсор на 0
2) Первый рендер
Запускаем функцию компонента в первый раз.
С каждым вызовом useState(), при первом запуске, в массив setters записывается сеттер-функция (с привязкой к позиции курсора), а затем state в массив state.
3) Последующий рендер
Каждый последующий рендер сбрасывает курсор, а те значения просто считываются из каждого массива.
4) Обработка событий
Каждый сеттер ссылается на свою позицию курсора. Поэтому вызов любого setter элемента будет менять значение state, в массиве state, в соответствии с позицией курсора.
«Наивная» реализация
Этот пример демонстрирует «наивную» реализацию:
Почему порядок так важен
Вопрос: что случится если мы изменим порядок хуков для цикла рендера, основываясь на некоем внешнем факторе или даже состоянии компонента?
Давайте проделаем то, что команда React не рекомендует делать:
Здесь у нас вызов useState находится внутри условия. Посмотрите к какому беспорядку это привело.
Плохой компонент. Первый рендер
На данный момент, экземпляры переменных firstName и lastName содержат верные данные, но посмотрите, что произойдёт на втором рендере:
Плохой компонент. Второй рендер
Теперь firstName и lastName содержат “Rudi”, так как state хранилище стало непоследовательным. Это не рабочий пример с явной ошибкой, но он даёт понимание, почему появились эти правила для хуков.
Команда React оговаривает правила использования, потому что их несоблюдение приведёт к несогласованности данных
Думайте о хуках, как о манипуляциях с массивами и не нарушайте правил
Теперь должно быть понятно, почему нельзя вызывать `use` хуки внутри условий и циклов. Потому что у нас будут проблемы с курсором, указывающим на соответствие в массивах. Если изменить порядок вызовов в течение рендера, курсор не будет указывать на верные данные или обработчики.
Управляйте хуками, думая о массивах, которым нужен курсор в правильном месте.
Заключение
Надеюсь, я смог пролить свет на то, что происходит под капотом API хуков. Помните о том, что истинная ценность здесь заключается в возможности группировать задачи. Поэтому внимательно относитесь к порядку и использованию API хуков. Это будет вознаграждено.
Hooks — это эффективный API плагин для React Components. Некоторые разработчики в восторге от его появления и на то есть причины. Если вы будете думать о состояниях, как о наборе массивов, то у вас не возникнет проблем с правилами React.
В будущем, надеюсь увидеть метод useEffects и сравнить его с методами жизненного цикла компонентов React.
Читайте нас в телеграмме и vk
Перевод статьи Rudi Yardley : React hooks: not magic, just arrays