Состояние: память компонента
Компонентам часто требуется изменять то, что отображается на экране, в результате взаимодействия. Ввод текста в форму должен обновлять поле ввода, нажатие кнопки «далее» в карусели изображений должно менять отображаемую картинку, нажатие «купить» должно добавлять товар в корзину. Компонентам нужно что-то «запоминать»: текущее значение ввода, текущее изображение, содержимое корзины. В React такая специфичная для компонента память называетсясостоянием.
Вы узнаете
- Как добавить переменную состояния с помощью хукаuseState
- Какую пару значений возвращает хук
useState - Как добавить более одной переменной состояния
- Почему состояние называется локальным
Когда обычной переменной недостаточно
Вот компонент, который отображает изображение скульптуры. Нажатие кнопки «Далее» должно показывать следующую скульптуру, изменяяindexна1, затем2и так далее. Однако этоне сработает(можете попробовать!):
Обработчик событияhandleClickобновляет локальную переменнуюindex. Но две вещи мешают увидеть это изменение:
- Локальные переменные не сохраняются между рендерами.Когда React рендерит этот компонент во второй раз, он делает это с нуля — он не учитывает никаких изменений локальных переменных.
- Изменения локальных переменных не запускают рендеры.React не понимает, что ему нужно снова отрендерить компонент с новыми данными.
Чтобы обновить компонент новыми данными, должны произойти две вещи:
- Сохранятьданные между рендерами.
- Запускатьповторный рендеринг компонента React с новыми данными.
ХукuseStateпредоставляет обе эти возможности:
- Переменнуюсостояниядля сохранения данных между рендерами.
- Функциюустановки состояниядля обновления переменной и запуска повторного рендеринга компонента React.
Добавление переменной состояния
Чтобы добавить переменную состояния, импортируйтеuseStateиз React в начале файла:
Затем замените эту строку:
на
index— это переменная состояния, аsetIndex— функция установки.
Синтаксис[ и ]здесь называетсядеструктуризацией массиваи позволяет читать значения из массива. Массив, возвращаемыйuseState, всегда содержит ровно два элемента.
Вот как они работают вместе вhandleClick:
Теперь нажатие кнопки «Далее» переключает текущую скульптуру:
Знакомство с вашим первым хуком
В ReactuseState, как и любая другая функция, начинающаяся с «use», называется хуком.
Хуки— это специальные функции, которые доступны только во времярендерингаReact (мы подробнее рассмотрим это на следующей странице). Они позволяют вам «подключаться» к различным функциям React.
Состояние — это лишь одна из таких функций, но другие хуки вы встретите позже.
Подводный камень
Хуки — функции, начинающиеся сuse— могут вызываться только на верхнем уровне ваших компонентов иливаших собственных хуков.Вы не можете вызывать хуки внутри условий, циклов или других вложенных функций. Хуки — это функции, но полезно думать о них как о безусловных декларациях о потребностях вашего компонента. Вы «используете» функции React в верхней части вашего компонента аналогично тому, как вы «импортируете» модули в верхней части вашего файла.
АнатомияuseState
Когда вы вызываетеuseState, вы сообщаете React, что хотите, чтобы этот компонент что-то запомнил:
В данном случае вы хотите, чтобы React запомнилindex.
Примечание
Соглашение заключается в том, чтобы называть эту пару какconst [something, setSomething]. Вы можете назвать её как угодно, но соглашения упрощают понимание между проектами.
Единственный аргумент дляuseState— этоначальное значениевашей переменной состояния. В этом примере начальное значениеindexустановлено в0с помощьюuseState(0).
Каждый раз, когда ваш компонент рендерится,useStateвозвращает вам массив, содержащий два значения:
- Переменнаясостояния(
index) со значением, которое вы сохранили. - Функцияустановки состояния(
setIndex), которая может обновить переменную состояния и заставить React снова отрендерить компонент.
Вот как это происходит на практике:
- Ваш компонент рендерится в первый раз.Поскольку вы передали
0вuseStateв качестве начального значения дляindex, он вернёт[0, setIndex]. React запоминает, что0— это последнее значение состояния. - Вы обновляете состояние.Когда пользователь нажимает кнопку, вызывается
setIndex(index + 1).indexравен0, поэтому этоsetIndex(1). Это говорит React запомнить, что теперьindexравен1, и запускает новый рендер. - Второй рендер вашего компонента.React по-прежнему видит
useState(0), но поскольку Reactпомнит, что вы установилиindexв1, он возвращает[1, setIndex]. - И так далее!
Несколько переменных состояния в компоненте
В одном компоненте может быть столько переменных состояния любого типа, сколько вам нужно. У этого компонента две переменные состояния: числоindexи логическое значениеshowMore, которое переключается при нажатии на «Показать подробности»:
Хорошей идеей является использование нескольких переменных состояния, если их состояния не связаны, какindex и showMoreв этом примере. Но если вы заметите, что часто изменяете две переменные состояния вместе, возможно, будет проще объединить их в одну. Например, если у вас есть форма со множеством полей, удобнее иметь одну переменную состояния, содержащую объект, чем переменную состояния для каждого поля. Дополнительные советы читайте в разделеВыбор структуры состояния.
Состояние изолировано и приватно
Состояние локально для экземпляра компонента на экране. Другими словами,если вы рендерите один и тот же компонент дважды, каждая копия будет иметь полностью изолированное состояние!Изменение состояния в одной копии не повлияет на другую.
В этом примере компонентGalleryиз предыдущего раздела рендерится дважды без изменений в его логике. Попробуйте нажать кнопки внутри каждой из галерей. Обратите внимание, что их состояния независимы:
Именно это отличает состояние от обычных переменных, которые вы можете объявить в начале модуля. Состояние не привязано к конкретному вызову функции или месту в коде, оно является «локальным» для конкретного места на экране. Вы отрендерили два компонента<Gallery />, поэтому их состояния хранятся отдельно.
Также обратите внимание, что компонентPageничего не «знает» о состоянииGalleryили даже о том, есть ли оно у него. В отличие от пропсов,состояние является полностью приватным для компонента, который его объявляет.Родительский компонент не может его изменить. Это позволяет добавлять состояние к любому компоненту или удалять его, не затрагивая остальные компоненты.
Что делать, если вы хотите, чтобы состояния обеих галерей были синхронизированы? Правильный способ сделать это в React —удалитьсостояние из дочерних компонентов и добавить его к их ближайшему общему родителю. Следующие несколько страниц будут посвящены организации состояния одного компонента, но мы вернёмся к этой теме в разделеОбмен состоянием между компонентами.
Резюме
- Используйте переменную состояния, когда компоненту нужно «запомнить» некоторую информацию между рендерами.
- Переменные состояния объявляются вызовом хука
useState. - Хуки — это специальные функции, начинающиеся с
use. Они позволяют вам «подключаться» к возможностям React, таким как состояние. - Хуки могут напомнить вам импорты: их нужно вызывать безусловно. Вызов хуков, включая
useState, допустим только на верхнем уровне компонента или другого хука. - Хук
useStateвозвращает пару значений: текущее состояние и функцию для его обновления. - У вас может быть несколько переменных состояния. Внутренне React сопоставляет их по порядку.
- Состояние является приватным для компонента. Если вы рендерите его в двух местах, каждая копия получает собственное состояние.
Try out some challenges
Challenge 1 of 4:Complete the gallery #
When you press “Next” on the last sculpture, the code crashes. Fix the logic to prevent the crash. You may do this by adding extra logic to event handler or by disabling the button when the action is not possible.
After fixing the crash, add a “Previous” button that shows the previous sculpture. It shouldn’t crash on the first sculpture.
