Использование хука состояния¶
Хуки — нововведение в 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
, похожего на методы жизненного цикла в классах. С его помощью компоненты могут выполнять побочные эффекты.