Для чего нужны хуки react
Краткий обзор хуков
Хуки — нововведение в React 16.8, которое позволяет использовать состояние и другие возможности React без написания классов.
Хуки — обратно совместимы. На этой странице вы получите общее представление о хуках. Имейте в виду, что это беглый обзор, который больше подойдёт опытным пользователям React. В конце каждого раздела есть вот такой жёлтый блок с детальным объяснением на случай, если вы запутались:
Если вы хотите понять, почему мы добавляем хуки в React, прочтите мотивацию.
Рассмотрим пример, в котором рендерится счётчик. Если вы нажмёте на кнопку, значение счётчика будет инкрементировано.
В этом примере, useState — это хук (определение хука дано ниже). Мы вызываем его, чтобы наделить наш функциональный компонент внутренним состоянием. React будет хранить это состояние между рендерами. Вызов useState возвращает массив с двумя элементами, который содержит: текущее значение состояния и функцию для его обновления. Эту функцию можно использовать где угодно, например, в обработчике событий. Она схожа с this.setState в классах, но не сливает новое и старое состояние вместе. Сравнение хука useState и this.state приводится на странице Использование хука состояния.
Объявление нескольких переменных состояния
Хук состояния можно использовать в компоненте более одного раза.
Хуки — это функции, с помощью которых вы можете «подцепиться» к состоянию и методам жизненного цикла React из функциональных компонентов. Хуки не работают внутри классов — они дают вам возможность использовать React без классов. (Мы не рекомендуем сразу же переписывать существующие компоненты, но при желании, вы можете начать использовать хуки в своих новых компонентах.)
Вам скорее всего доводилось ранее запрашивать данные, делать подписки или вручную менять DOM из React-компонента. Мы расцениваем эти операции как «побочные эффекты» (или сокращённо «эффекты»), так как они могут влиять на работу других компонентов и их нельзя выполнить во время рендера.
К примеру, этот компонент устанавливает заголовок документа после того, как React обновляет DOM:
При необходимости вы можете вернуть из эффекта функцию, которая указывает эффекту, как выполнить за собой «сброс». Например, этот компонент использует эффект, чтобы подписаться на статус друга в сети, и выполняет сброс, отписываясь от него.
Хуки дают вам возможность организовать побочные эффекты в компоненте по связанным частям (например, добавление или отмена подписки), вместо того, чтобы принуждать вас делить всё согласно методам жизненного цикла.
Вы можете узнать больше о useEffect на странице Использование хука эффекта.
Хуки — это функции JavaScript, которые налагают два дополнительных правила:
Мы разработали специальный плагин для линтера, который помогает обеспечивать соблюдение этих правил. Мы понимаем, что эти правила могут показаться немного непонятными и накладывать определённые ограничения, но они очень важны для правильной работы хуков.
Вы можете узнать больше на странице Правила хуков.
💡 Создание собственных хуков
Иногда нужно повторно использовать одинаковую логику состояния в нескольких компонентах. Традиционно использовались два подхода: компоненты высшего порядка и рендер-пропсы. С помощью пользовательских хуков эта задача решается без добавления ненужных компонентов в ваше дерево.
Прежде всего, давайте извлечём эту логику в пользовательский хук useFriendStatus
Хук принимает friendID в качестве аргумента и возвращает переменную, которая показывает, в сети наш друг или нет.
Теперь мы можем использовать этот хук в обоих наших компонентах:
Состояния каждого компонента никаким образом не зависят друг от друга. Хуки — это способ использовать повторно логику состояния, а не само состояние. Более того, каждое обращение к хуку обеспечивает совершенно изолированное состояние. Вы даже можете использовать один и тот же хук несколько раз в одном компоненте.
Пользовательские хуки — это в большей степени соглашение, чем дополнение. Если имя функции начинается с ” use ” и она вызывает другие хуки, мы расцениваем это как пользовательский хук. Если вы будете придерживаться соглашения useSomething при именовании хуков, это позволит нашему плагину для линтера найти баги в коде, который использует хуки.
Есть много подходящих случаев, чтобы написать пользовательские хуки, такие как работа с формами, анимация, декларативные подписки, таймеры и, наверное, много других, о которых мы даже не думали. Мы с нетерпением ожидаем увидеть, какие же пользовательские хуки сообщество React сможет придумать.
А хук useReducer даёт возможность управлять внутренним состоянием более сложного компонента с помощью редюсера.
Вы можете узнать больше обо всех встроенных хуках на странице API-справочника хуков.
Фух, давайте перестанем торопиться и немного охладим пыл! Если вам что-то непонятно или вы хотите узнать о чём-либо более подробно, вы можете начать читать следующие страницы, начиная с документации хука состояния.
Вы также можете просмотреть API-справочник хуков и FAQ хуков.
И наконец, не проходите мимо вступительной страницы, на которой вы узнаете почему мы добавляем хуки и как мы планируем использовать их вместе с классами без необходимости переписывать наши приложения.
Хуки — это лучшее, что случилось с React
React — это самая популярная фронтенд-библиотека из экосистемы JavaScript. Она известна простотой использования и читабельностью кода, создаваемого с её применением. Это позволяет организациям самых разных масштабов успешно внедрять данную библиотеку. Но компоненты, основанные на классах, это громоздкие конструкции, с которыми непросто разобраться. Хуки позволяют работать с состоянием компонентов, с методами их жизненного цикла, с другими механизмами React без использования классов.
В этой статье мы поговорим о том, что такое React-хуки, о том, что отличает их от других механизмов библиотеки, и о том, почему они — это лучшее, что случилось с React.
О возникновении хуков React
Изначально в библиотеке React использовались, в основном, компоненты, основанные на классах. Применение таких компонентов может потребовать приложения чрезмерных усилий в ходе разработки, так как программисту постоянно приходится переключаться между классами, компонентами высшего порядка, свойствами рендеринга. А с появлением хуков React можно, решая те же задачи, что и раньше, не переключаясь между различными механизмами, просто пользоваться функциональными компонентами. Хуки значительно улучшили React из-за того, что с их помощью можно писать код, который получается проще, чем код, который писали раньше, но при этом позволяет быстрее и эффективнее реализовывать похожий функционал. А ещё можно, не пользуясь классами, работать с состоянием компонентов и с методами их жизненного цикла.
Вот примеры кода, иллюстрирующие использование компонентов, основанных на классах, и функциональных компонентов.
Компонент, основанный на классах:
Этот компонент выводит в DOM элемент
А вот — код функционального компонента, решающего ту же задачу.
Да, обратите внимание на то, что хуки нельзя использовать в компонентах, основанных на классах.
Как хуки упрощают работу с методами жизненного цикла компонентов?
Среди методов жизненного цикла React-компонента можно отметить те, которые вызываются при его монтировании, обновлении и размонтировании.
Изначально эти методы можно было использовать только при применении компонентов, основанных на классах. Это обычно было связано с необходимостью работать с кодом, который достаточно сложно писать и читать. Если же пользоваться функциональными компонентами и хуками — решение тех же задач упрощается.
Предположим, нам нужно загрузить данные с использованием метода жизненного цикла componentDidMount() в компоненте, основанном на классах:
А теперь решим ту же задачу в функциональном компоненте, пользуясь хуками useState и useEffect :
Хуки облегчили изучение React
Компоненты, основанные на классах, всегда были несколько громоздкими и непонятными конструкциями, особенно учитывая то, что их применение ведёт к тому, что механизмы управления состоянием компонента и многократного использования кода кажутся сложнее, чем они есть на самом деле. Это привело к тому, что многие новички избегали React, выбирая более «лёгкие» библиотеки и фреймворки. А с появлением хуков изучить React стало легче, чем прежде. Это стало одной из причин роста популярности React.
На этом графике виден постоянный рост интереса к React на Stack Overflow, продолжающийся уже много лет. Здесь же можно сравнить процент вопросов о React с процентом вопросов о других популярных JavaScript-инструментах. Этот график доказывает то, что разработчики стали чаще пользоваться библиотекой React после появления хуков.
О некоторых хуках и их предназначении
▍Хук useState
Вероятно, useState — это самый распространённый React-хук. Он позволяет работать с переменными состояния в функциональных компонентах.
Здесь useState принимает единственный аргумент: исходное значение состояния. Он возвращает массив с переменной state и с функцией для обновления этого состояния. После этого у программиста есть всё, что нужно для работы с состоянием в функциональном компоненте.
▍Хук useEffect
Хук useEffect помогает программисту выполнять побочные эффекты в функциональных компонентах. То есть — вызывать функции, которые нужно выполнить после обновления DOM. Он заменяет некоторые события, позволяя вызывать функцию при изменении одной или нескольких переменных. Он принимает два аргумента: функцию и необязательный массив. Эта функция определяет то, какой именно «побочный эффект» нужно выполнить, а в массиве указывают переменные, за изменениями которых нужно наблюдать.
▍Другие хуки
Итоги
Мы, при создании React-компонентов, пользовались классами из-за того, что в своё время для работы с состоянием или для реализации методов жизненного цикла нельзя было воспользоваться функциональными компонентами. Хуки React значительно упростили решение старых задач, дав нам возможность писать код, который отличается лучшей пригодностью к созданию нового функционала методом композиции, который получается гибче, чем прежде, который легче расширять. Многие компании используют React в роли своей основной фронтенд-библиотеки, что приводит к тому, что всё больше и больше разработчиков осваивают React.
Пользуетесь ли вы хуками React в своих проектах?
React hooks — победа или поражение?
С выходом нового React 16.6.0 в документации появился HOOKS (PROPOSAL). Они сейчас доступны в react 17.0.0-alpha и обсуждаются в открытом RFC: React Hooks. Давайте разберемся что это такое и зачем это нужно под катом.
Да это RFC и вы можете повлиять на конечную реализацию обсуждая с создателями react почему они выбрали тот или иной подход.
Давайте взглянем на то как выглядит стандартный хук:
Попробуйте обдумать этот код, это тизер и к концу статьи вы уже будете понимать, что он означает. Первое, что стоит знать, что это не ломает обратную совместимость и возможно их добавят в 16.7 после сбора обратной связи и пожеланий в RFC.
Как уверяют ребята, это не план по выпиливанию классов из реакта.
Так же хуки не заменяют текущие концепции реакта, все на месте props/state/context/refs. Это всего лишь еще один способ использовать их силу.
Мотивация
Хуки решают на первый взгляд не связные проблемы, которые появились при поддержке десятков тысяч компонентов в течении 5 лет у facebook.
Самое сложное это переиспользовать логику в stateful компонентах, у реакта нет способа прикрепить многоразовое поведение к компоненту(например подключить его к хранилищу). Если вы работали с React вам известно понятие HOC(high-order-component) или render props. Это достаточно хорошие паттерны, но иногда они используются чрезмерно, они требуют реструктуризации компонентов, для того, чтобы их можно было использовать, что обычно делает код более громоздким. Стоит посмотреть на типичное реакт приложение и станет понятно о чем идет речь.
Это называется wrapped-hell — ад оберток.
Приложение из одних HOC это нормально в текущих реалиях, подключили компонент к стору/теме/локализации/кастомным хокам, я думаю это всем знакомо.
Становится понятно, что реакту необходим другой примитивный механизм для разделения логики.
Хуки позволяют делать тоже самое разбивая логику между компонентами на маленькие функции и использовать их внутри компонентов.
Классы сложны для людей и для машин
Особенно если не ограничиваться шаблонами, не так давно ребята из реакта эксперементировали с компоновкой компонентов c Prepack и увидели многообещающие результаты, но тем не менее компоненты класса позволяют создавать непреднамеренные плохие паттерны, которые заставляют эти оптимизации исчезать, так же классы не очень хорошо мигрируют и при горячей перезагрузке классы делают ее ненадежной. В первую очередь ребятам хотелось предоставить API которое поддерживает все оптимизации и отлично работает с горячей перезагрузкой.
Глянем на хуки
State hook
Код ниже рендерит параграф и кнопку и если мы нажмем на кнопку то значение в параграфе будет инкрементировано.
таким образом мы создаем сразу несколько состояний и нам не нужно думать о том, чтобы их как то декомпозировать. Таким образом можно выделить, что хуки это функции которые позволяют «подключаться» к фишкам классовых компонентов, так же хуки не работают внутри классов, это важно запомнить.
Effect hook
Часто в классовых компонентах, мы делаем side effect функции, например подписываемся на события или делаем запросы за данными, обычно для этого мы используем методы componentDidMount / componentDidUpdate
Когда мы вызываем useEffect мы говорим реакту сделать ‘side effect’ после обновления изменений в DOM дереве. Эффекты объявляются внутри компонента, поэтому имеют доступ к props/state. Причем их мы можем точно так же создавать сколько угодно.
Сразу же стоит обратить внимание на второй side effect в нем мы возвращаем функцию, делаем мы это для того, чтобы выполнить какие то действия после того как компонент выполняет unmount, в новом api это называют эффекты с очисткой. Остальные эффекты могут возвращать, что угодно.
Правила хуков
Хуки это просто javascript функции, но они требуют всего двух правил:
Кастомные хуки
В тоже время нам хочется переиспользовать логику stateful компонентов, обычно для этого используют либо HOC либо render props паттерны, но они создают дополнительный объем нашего приложения.
Например опишем следующую функцию:
Осознайте этот код, это будет кастомный хук, который мы можем вызывать в различных компонентах. Например так:
В любом случае, мы переиспользуем состояние компонента, каждый вызов функции useFriendStatus создает изолированное состояние. Так же стоит отметить, что начало этой функции начинается со слова use это говорит о том, что это хук. Советуем соблюдать этот формат. Вы можете писать кастомные хуки на что угодно, анимации/подписки/таймеры и много многое другое.
Есть еще пара хуков.
useContext
useContext позволяет использовать вместо renderProps обычное возвращаемое значение, в него следует передать контекст который мы хотим извлечь и он нам его вернет, таким образом мы можем избавиться от всех HOC, которые передавали context в props.
И теперь объект контекста мы можем просто использовать в возвращаемом значении.
useCallback
Как часто вам приходилось создавать компонент класса только для того, чтобы сохранить ссылку на метод? Этого больше не нужно делать, мы можем использовать useCallback и наши компоненты не будут перерисовываться потому что пришла новая ссылка на onClick.
useMemo
Возвращаем мемоизированное значение, мемоизированное значит вычисляется только тогда, когда один из аргументов поменялся, второй раз одно и тоже вычисляться не будет.
Да тут приходится дублировать значения в массиве, чтобы хук понял, что они не изменились.
useRef
useImperativeMethods
useImperativeMethods кастомизирует значение экземпляра который передается из родителя и использует ref напрямую. Как всегда следует избегать передачу ссылок на прямую и следует использовать forwardRef
useMutationEffect
useMutationEffect очень похож на useEffect за исключением того что он запускается синхронно на том этапе когда реакт изменяет значения DOM, прежде чем соседние компоненты будут обновлены, этот хук следует использовать для выполнения DOM мутаций.
Лучше предпочитать useEffect чтобы предотвратить блокировку визуальных изменений.
useLayoutEffect
useLayoutEffect так же похож на useEffect за исключением того, что запускается синхронно после всех обновлений DOM и синхронного ре-рендера. Обновления запланированные в useLayoutEffect применяются синхронно, до того как браузер получит возможность отрисовать элементы. Так же следует стараться использовать стандартный useEffect чтобы не блокировать визуальные изменения.
useReducer
useReducer — это хук для создания редюсера который возвращает состояние и возможность диспатчить изменения:
Так же useReducer принимает 3 аргумент, это action который должен выполнятся при инициализации редюсера:
Так же мы можем создать контекст в данным редюсером и через хук useContext использовать его во всем приложении, это остается на домашнее задание.
Подводя итог
Хуки достаточно мощный подход по решению wrapper-hell и решают несколько проблем, но все их можно свети с одному определению передача ссылок. Уже сейчас начинают появляться сборники хуков по использованию или этот сборник. Более подробнее с хуками можно познакомиться в документации.
Введение в хуки
Хуки — нововведение в React 16.8, которое позволяет использовать состояние и другие возможности React без написания классов.
Вы можете начать изучать хуки на следующей странице. Здесь же мы расскажем, зачем мы добавили хуки в React, и как они помогут вам писать приложения.
React 16.8.0 это первый релиз, поддерживающий хуки. При обновлении версии, не забудьте обновить и все зависимости, включая React DOM. Поддержка хуков в React Native появилась в версии 0.59.
На конференции React Conf 2018, Софи Алперт (Sophie Alpert) и Дэн Абрамов (Dan Abramov) представили хуки, а Райн Флоренс (Ryan Florence) показал, как их использовать в приложении. Видео конференции можно посмотреть здесь:
Полная обратная совместимость
Перед тем, как мы продолжим, обратите внимание, что хуки:
Мы не планируем удалять классы из React. Вы можете прочитать больше о стратегии постепенного внедрения хуков в разделе ниже.
Хуки не меняют ваши знания о концепциях в React. Вместо этого, хуки предоставляют более прямой доступ к API уже знакомых вам понятий: пропсов, состояния, контекста, рефов, и жизненного цикла. Мы также рассмотрим мощный способ компоновать эти понятия с помощью хуков.
Чтобы начать изучать хуки, перейдите на следующую страницу! На этой странице мы расскажем о том, зачем нужны хуки, и как их использовать, не переписывая наши приложения.
Хуки решают множество, казалось бы, несвязанных между собой, проблем в React, с которыми мы сталкивались в течение пяти лет написания и поддержки десятков тысяч компонентов. Если вы изучаете React, используете его ежедневно или используете другую библиотеку с похожим компонентным подходом, эти проблемы наверняка покажутся вам знакомыми.
Трудно повторно использовать логику состояний между компонентами
В React нет способа «присоединить» повторно используемое поведение к компоненту (например, подключение к хранилищу). Если вы работали с React какое-то время, то вам могут быть знакомы такие паттерны, как рендер-пропсы и компоненты высшего порядка, которые пытаются решить эту проблему. Но эти паттерны заставляют вас изменять структуру компонентов, что делает код громоздким и трудным в поддержке. Если вы посмотрите на типичное React-приложение в React DevTools, то увидите «ад обёрток» из компонентов, окружённых провайдерами, консьюмерами, компонентами высшего порядка, рендер-пропсами и другими абстракциями. Хоть мы и можем отфильтровать их в DevTools, всё это указывает на более глубокую проблему в React. Нужен более удобный способ повторно использовать логику вокруг состояния.
С помощью хуков вы можете извлечь логику состояния из компонента, чтобы её протестировать или повторно использовать. Хуки позволяют вам повторно использовать логику состояния, не затрагивая дерево компонентов. Благодаря этому, хуки легко использовать в разных компонентах и делиться ими с сообществом.
Мы обсудим это подробнее в разделе Создание собственных хуков.
Сложные компоненты становятся трудными для понимания
В некоторых случаях невозможно разбить компоненты на более мелкие, потому что логика состояния раскидана повсюду. Такие компоненты сложно тестировать. Это одна из причин, по которой люди предпочитают использовать в React отдельную библиотеку для управления состоянием. Однако, это добавляет множество абстракций, заставляет прыгать между разными файлами и усложняет повторное использование компонентов.
Чтобы решить эту проблему, хуки позволяют разбить один компонент на маленькие функции по их назначению (например, подписке или загрузке данных), а не на основе методов жизненного цикла. Вы также можете контролировать внутреннее состояние с помощью редюсера, чтобы поведение было более предсказуемым.
Классы путают как людей, так и машины
Вдобавок к усложнению организации кода и его повторного использования, классы создают существенный барьер в изучении React. Нужно понимать, как работает this в JavaScript, поведение которого отличается от большинства языков. Приходится помнить про привязку контекста для обработчиков событий. Без использования нестабильных синтаксических предложений, код становится многословным. Люди могут прекрасно понимать пропсы, состояние и однонаправленный поток данных, но всё равно путаться с классами. Различия между функциональными и классовыми компонентами в React и тем, когда их использовать, приводят к разногласиям даже между опытными React-разработчиками.
Вдобавок, React существует уже около пяти лет и мы хотим убедиться, что он останется актуальным в течение следующих пяти лет. Как показывают Svelte, Angular, Glimmer и другие технологии, компиляция компонентов перед их исполнением имеет огромный потенциал в будущем. Особенно, если шаблоны не накладывают ограничений. Недавно мы экспериментировали со свёртыванием компонентов с использованием Prepack и увидели первые многообещающие результаты. Однако мы заметили, что классовые компоненты могут приводить к ненамеренным паттернам, сводящим оптимизации на нет. Классы создают сложности для инструментов и сегодня. Например, классы плохо минифицируются, а горячая перезагрузка (hot reloading) ненадёжна и часто ломает их. Наша цель — предоставить API, который повысит вероятность того, что код можно будет оптимизировать.
Чтобы решить эти проблемы, хуки позволяют использовать больше возможностей React без написания классов. Концептуально, React-компоненты всегда были ближе к функциям. Хуки обеспечивают доступ к функционалу, но не обесценивают опыт использования React. Хуки предоставляют императивные лазейки и не требуют от вас изучения сложных функциональных или реактивных подходов.
Обзор хуков — хорошее начало для изучения хуков.
Стратегия постепенного внедрения
TLDR: Мы не планируем удалять классы из React.
Мы знаем, что React-разработчики сфокусированы на поставке продукта и у них нет времени изучать новый API каждого релиза. Хуки это что-то новое, и возможно, лучше подождать больше примеров и уроков, прежде чем начинать их изучение.
Мы также понимаем, что планка для добавления новых примитивов в React очень высока. Поэтому для любопытных читателей мы подготовили подробный RFC, в котором можно найти больше информации о технических аспектах выбранного дизайна.
Важно понимать, что хуки работают рядом с существующим кодом, поэтому вы можете внедрять их постепенно. Нет спешки переходить на хуки. Мы рекомендуем избегать любых «больших переписываний», особенно для существующих, сложных классовых компонентов. Вам потребуется немного изменить мировоззрение, чтобы начать «мыслить хуками». По нашему опыту, лучше всего сначала попрактиковаться использовать хуки в новых и некритичных компонентах и убедиться, что все в вашей команде чувствуют себя комфортно с ними. После того, как вы попробуете, не стесняйтесь отправить нам свой отзыв, позитивный или негативный.
Мы намерены охватить все возможные варианты использования классов в хуках, но мы всё ещё будем поддерживать классовые компоненты в обозримом будущем. В Facebook десятки тысяч компонентов, написанных в виде классов, и у нас нет абсолютно никаких планов их переписывать. Вместо этого мы начинаем использовать хуки в новом коде параллельно с классами.
Часто задаваемые вопросы
Мы подготовили для вас страницу FAQ с ответами на самые частые вопросы о хуках.
К концу этой страницы вы должны иметь общее представление о том, какие проблемы решают хуки, но многие детали, возможно, остались непонятны. Не беспокойтесь! Давайте перейдём на следующую страницу, где мы изучим хуки на примерах.