Управление функциональными компонентами Введение в хуки
Скачать 0.6 Mb.
|
Глава 4 Управление функциональными компонентами Введение в хуки Хуки позволяют определять и использовать состояние и другие возможности React без создания классов. По сути хуки представляют функции, которые позволяют подключиться к состоянию и другим возможностям, которые есть в React. Мы можем создавать свои хуки, однако React по умолчанию уже предоставляет ряд встроенных хуков: useState: предназначен для управления состоянием компонентов useEffect: предназначен для перехвата различного рода изменений в компонентах, которые нельзя обработать внутри компонентов useContext: позволяет подписываться на контекст React useReducer: позволяет управлять локальным состоянием сложных компонентов useCallback: позволяет управлять функциями обратного вызова useMemo: предназначен для управления мемоизированными (грубо говоря кэшированными) значениями useRef: возвращать некоторое изменяемое значение, например, ссылку на html-элементы DOM, которыми затем можно управлять в коде JavaScript useImperativeHandle: настраивает объект, который передается родительскому компоненту при использовании ref useLayoutEffect: аналогичен хуку useEffect(), но вызывается синхронно после всех изменений в структуре DOM useDebugValue: предназначен для отображения некоторого значения в целях отладки useId: предназначен для генерации уникального идентификатора useTransition: применяется для создания переходов при рендеринге useDeferredValue: позволяет отложить рендеринг некритичных частей структуры DOM useSyncExternalStore: предназначен для синхронизации данных с внешними хранилищами useInsertionEffect: предназначен для библиотек, которые используют CSS в JS, для оптимизации при внедрении стилей при рендеринге Переход от классов к хукам Рассмотрим простейший пример, как мы можем перейти от классов к хукам. Допустим, у нас есть следующий класс-компонент: Здесь определен компонент ClickButton, который принимает через props некоторое значение increment. В конструкторе определяется состояние в виде переменной counter, которая равна 0. Кроме того, в классе определяется метод press(), в котором изменяется состояние компонента. Для изменения состояния вызывается другой метод - incrementCounter, который берет из props значение increment и использует его для увеличения значения переменной counter. В коде класса-компонента определяется кнопка, по нажатию на которую как раз и вызывается метод press():
В итоге по нажатию на кнопку мы получим увеличение переменной counter: Теперь определим аналогичный компонент с использованием хуков: В данном случае определен функциональный компонент ClickButtonHook, так как мы не можем использовать хуки в классах-компонентах, а только в функциях. Вначале определяем переменные состояния: В данном случае определяются две переменных: count и setCount. Переменная count хранит состояние компонента, а переменная setCount позволяет изменять значение переменной count. В функцию useState() передается число 0 - это то значение, которое по умолчанию получает переменная count. Для изменения состояния в компоненте определена функция press(), которая выполняет выражение setCount(count + props.increment); - к переменной count прибавляется значение increment из props. Это выражение (count + props.increment) и определяет новое значение переменной count. Таким образом, состояние компонента ClickButtonHook будет изменено. В коде также определена кнопка, по нажатию на которую вызывается метод press(). В итоге мы получим ту же программу, но с использованием хуков. И как видно, этот код несколько короче, чем код класса-компонента. Подключение хуковВ примере выше библиотека React подключалась непосредственно на веб-страницу, где и определен весь код приложения. Однако если компоненты расположены в отдельных файлах, то мы можем импортировать хук useState (впрочем как и другие встроенные хуки) следующим образом: Ограничения при использовании хуковХуки имеют ряд ограничений при определении и использовании: Хуки вызываются только на верхнем уровне (top-level) компонента. Они НЕ вызываются внутри циклов, условных конструкций, внутри стандартных функций javascript. Хуки можно вызывать только из функциональных компонентов React, либо из других хуков. Но их нельзя вызывать из классов-компонентов. Функциональные компоненты можно определять как обычные функции: Хук useStateОдним из наиболее используемых встроенных хуков является useState, который позволяет определить состояние компонента. Например, определим простейший компонент, который применяет этот хук: Итак, здесь определен компонент Counter, причем определен в виде функции, так как мы не можем использовать хуки в классах-компонентах. Вначале определяем переменные состояния: В данном случае определяются две переменных: count и setCount. Переменная count собственно хранит состояние - некоторый объект, а переменная setCount представляет функцию, которая позволяет изменять значение переменной count. Несмотря на то, что между названиями переменных есть связь - count и setCount, однако это не более чем условность. Названия переменных могут быть вообще никак между собой не связаны. Что за значение будет хранить переменная count? А хранит она то значение, которое передается в функцию useState() - в данном случае это число 0. Чтобы инспектировать значение переменной count, ее значение выводится в заголовке h3: В коде компонента определена кнопка, которая по нажатию будет вызывать изменение значения переменной count В данном случае применяется стрелочная функция, которая выполняет выражение setCount(count + 1), которое увеличивает значение count на единицу. В итоге по нажатию на кнопку изменится значение переменной count: Определение переменных состоянияИтак, хук useState определяет переменные состояния. Единственный аргумент хука определяет начальное значение переменной состояния. А возвращает useState() массив из двух объектов. Первый объект представляет значение состояния, а второй объект представляет функцию, которая обновляет это значение. Например, выше состояние определялось следующим образом: В данном случае для определения переменных применяется синтаксис декомпозиции или destructuring. Но также мы могли бы использовать и стандартный синтаксис массивов для получения значений переменных: Определение нескольких переменных состоянияПри необходимости можно определять множество переменных состояния. Например: В данном случае определены две переменных состояния: name и age. Также мы можем изменять значения этих переменных. Например, добавим к предыдущему примеру изменение переменных: В данном случае для обновления значений переменных name и age в компоненте определены два поля ввода. Событие onChange каждого поля привязано к одной из функций компонента - handleAgeChange или handleNameChange. Поэтому изменение значения в каждом поле вызовет соответствующую функцию. Например, при вводе текста для имени пользователя будет вызываться функция handleNameChange(): По умолчанию в функцию обработки события поля ввода input передается информация о событии, из которой с помощью свойства target.value мы можем получить введенное значение и затем передать его в функцию изменения состояния: setName(event.target.value) Однако нам необязательно определять отдельные переменные для хранения состояния. Хук useState равным образом позволяет определять массивы и комплексные объекты. Например, перепишем предыдущий пример, объединив переменные в один объект: Здесь состояние компонента представлено сложным объектом, который имеет два свойства: name и age. Но в данном случае при обновлении следует учитывать, что функция обновления (в данном случае - setUser) полностью изменяет хранимое значение состояния, поэтому нам надо полностью переопределить его свойства: В итоге мы получим тот же результат: Однако если у нас объект имеет множество свойств, то перечисление всех свойств и их значений может быть утомительным. И в этом случае мы можем сократить запись с помощью spread-оператора ...: |