Использование хука состояния¶
Хуки — нововведение в React 16.8, которое позволяет использовать состояние и другие возможности React без написания классов.
На странице введения в хуки мы познакомились с ними на этом примере:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Давайте начнём изучать хуки, сравнив этот код с эквивалентным кодом на основе класса.
Эквивалентный пример с классом¶
Если вы уже пользовались классами в React, то вам знаком такой код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
Сначала состояние выглядит как { count: 0 }. Каждый раз, когда пользователь кликает, мы увеличиваем state.count на единицу, вызывая this.setState(). Мы будем использовать фрагменты этого класса на протяжении всей страницы.
Примечание
Возможно, вы спросите себя, почему мы используем в качестве примера счётчик, а не что-то более реалистичное. Дело в том, что мы хотим обратить ваше внимание на API, одновременно делая первые шаги с хуками.
Хуки и функциональные компоненты¶
Напоминаем, что функциональные компоненты в React выглядят так:
1 2 3 4 | |
или так:
1 2 3 4 | |
Возможно, вы слышали, что такие компоненты называются «компонентами без состояния». Сейчас мы покажем, как использовать внутри них состояние React, поэтому будем называть их «функциональными компонентами».
Хуки НЕ работают внутри классов, а используются вместо них.
Что такое хук?¶
Наш новый пример начинается с того, что импортирует хук useState из React:
1 2 3 4 5 | |
Что такое хук? Хук — это специальная функция, которая позволяет «подцепиться» к возможностям React. Например, хук useState предоставляет функциональным компонентам доступ к состоянию React. Мы узнаем про другие хуки чуть позже.
Когда применить хук? Раньше, если вы писали функциональный компонент и осознавали, что вам нужно наделить его состоянием, вам приходилось превращать этот компонент в класс. Теперь же вы можете использовать хук внутри существующего функционального компонента. Мы покажем это прямо сейчас!
Примечание:
Есть специальные правила о том, где можно, а где нельзя использовать хуки внутри компонента. Их мы изучим в главе Правила хуков.
Объявление переменной состояния¶
Допустим, мы хотим инициализировать в классе состояние count значением 0. Для этого в его конструкторе присваиваем this.state объект { count: 0 }:
1 2 3 4 5 6 7 | |
В функциональном компоненте нам недоступен this, поэтому мы не можем задать или считать состояние через this.state. Вместо этого мы вызываем хук useState напрямую изнутри нашего компонента.
1 2 3 4 5 | |
Что делает вызов useState? Он объявляет «переменную состояния». Мы называли переменную count, но могли дать ей любое имя, хоть банан. Таким образом мы можем «сохранить» некоторые значения между вызовами функции. useState это новый способ использовать те же возможности, что даёт this.state в классах. Обычно переменные «исчезают» при выходе из функции. К переменным состояния это не относится, потому что их сохраняет React.
Какие аргументы передавать useState? Единственный аргумент useState это исходное состояние. В отличие от случая с классами, состояние может быть и не объектом, а строкой или числом, если нам так удобно. Поскольку в нашем примере отслеживается количество сделанных пользователем кликов, мы передаём 0 в качестве исходного значения переменной. (Если нам нужно было бы хранить два разных значения в состоянии, то пришлось бы вызвать useState() дважды.)
Что возвращается из useState? Вызов useState вернёт пару значений: текущее состояние и функцию, обновляющую состояние. Поэтому мы пишем const [count, setCount] = useState(). Это похоже на this.state.count и this.setState в классах, с той лишь разницей, что сейчас мы принимаем их сразу в паре. Если вам незнаком использованный синтаксис, мы вернёмся к нему ближе к концу страницы.
Теперь мы знаем, что делает useState, и пример должен быть ясен:
1 2 3 4 5 | |
Мы объявляем переменную состояния count и устанавливаем ей значение 0. React будет помнить текущее (наиболее свежее) значение между рендерингами и передавать его нашей функции. Если мы захотим изменить count, мы вызовем setCount.
Примечание
Может быть, вы спросите себя, почему
useStateне назвалиcreateState?Слово «create» («создать») было бы не совсем точно, потому что состояние создаётся только в момент, когда компонент рендерится впервые. В последующие же рендеринги
useStateвозвращает текущее состояние. Иначе не существовало бы «состояния» как такового. Названия всех хуков начинаются с «use» тоже неспроста. О причине мы узнаем из Правил хуков.
Чтение состояния¶
Когда мы хотим отобразить текущее состояние счётчика в классе, мы обращаемся к this.state.count:
1 | |
В функции же мы можем использовать count напрямую:
1 | |
Обновление состояния¶
В классе мы вызываем this.setState(), когда надо обновить состояние count:
1 2 3 4 5 6 7 | |
В функции нам не нужен this, потому что setCount и count уже доступны как переменные:
1 2 3 | |
Резюме¶
Давайте построчно пробежимся по тому, что мы выучили и проверим наши знания:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
- Строка 1: Импортируем хук
useStateиз React. Он позволяет функциональному компоненту хранить внутреннее состояние. - Строка 4: Объявляем внутри компонента
Exampleновую переменную состояния, вызвав хукuseState. Этот вызов возвращает пару значений, которым мы даём имена. Поскольку наша переменная состояния хранит количество сделанных по кнопке кликов, мы называем еёcount. Чтобы проинициализировать её, мы передаём значение0в качестве единственного аргумента функцииuseState. Второе возвращённое нам значение позволяет обновлятьcount, поэтому мы называем еёsetCount. - Строка 9: Когда пользователь кликает по кнопке, мы вызываем
setCountс приращённым значением. После этого React сделает повторный рендер, в котором использует уже новое значениеcount.
Поначалу это всё может показаться слишком сложным. Не торопитесь! Если вы запутались в объяснении, ещё раз прочитайте приведённый код с начала до конца. Обещаем, если вы на минутку «забудете», как состояние работает в классах, и посмотрите на код свежим взглядом, всё станет ясно.
Совет: Что делают квадратные скобки?¶
Вы могли обратить внимание на квадратные скобки в месте, где объявляется переменная состояния:
1 | |
Два имени в квадратных скобках не содержатся в API React. Названия переменным состояния выбираете вы:
1 | |
Такой синтаксис в JavaScript называется «деструктуризацией массивов (array destructuring)». Он означает, что мы создаём две новые переменные, fruit и setFruit. Во fruit будет записано первое значение, вернувшееся из useState, а в setFruit — второе, что равносильно такому коду:
1 2 3 | |
Когда мы объявляем переменную состояния с помощью функции useState, мы получаем от неё пару, то есть массив из двух элементов. Первый элемент обозначает текущее значение, а второй является функцией, позволяющей менять это значение. Доступ к элементам через [0] и [1] менее ясен, потому что индексы лишены осмысленных имён.
Примечание
Вам может быть любопытно, а как же React знает, какому компоненту соответствует какой вызов
useState, если мы не передаём React ниthisни чего-либо подобного. Ответ на этот и многие другие вопросы мы дадим в FAQ.
Совет: Использование нескольких переменных состояния¶
Объявлять переменные состояния через пару [something, setSomething] удобно ещё и тем, что когда нам нужны несколько переменных, мы можем назвать каждую из них собственным именем:
1 2 3 4 5 | |
В примере выше мы видим локальные переменные age, fruit и todos, которые можем обновлять независимо друг от друга:
1 2 3 4 | |
Использовать несколько переменных состояния совсем не обязательно, потому что они могут быть объектами или массивами, которые группируют связанные по смыслу данные. Обратите внимание, что, в отличие от this.setState в классах, обновление переменной состояния всегда замещает её значение, а не осуществляет слияние.
Подробные рекомендации о разделении независимых переменных состояния вы найдёте в FAQ.
Следующие шаги¶
На этой странице мы изучили хук React под названием useState. Иногда мы будем ссылаться на него как на «хук состояния». Он позволяет добавить состояние в функциональные компоненты React, в чём мы убедились на примере!
Мы узнали ещё немного больше о хуках — функциях, позволяющих функциональным компонентам «подцепиться» к возможностям React. Их имена всегда начинаются с use. Существует много других хуков, которые мы пока не рассматривали.
А теперь давайте перейдём к изучению хука useEffect, похожего на методы жизненного цикла в классах. С его помощью компоненты могут выполнять побочные эффекты.