В React разработчики могут совершено свободно управлять состоянием внутри компонента. Существуют два типа компонентов: классовые и функциональные, которые были представлены в React v16.
В классовых компонентах используются такие методы, как this.state
и this.setState
для состояния, а также componentDidMount()
для запуска побочного эффекта после монтирования компонента. Подробнее об этом можно прочитать здесь.
Однако в этой статье мы уделим внимание функциональным компонентам, так как большинство пользователей React работают с ними и их состоянием, которое управляется с помощью хуков.
В этой статье рассмотрим лучшие способы для управления состоянием в функциональных компонентах, а также по-настоящему задействуем хуки API.
useReducer для сложного состояния
Иногда хука useState
бывает недостаточно, особенно при работе со сложным состоянием, которое может включать большие объекты. В таких случаях лучше подойдет useReducer
— мощный хук React, не требующий установки сторонних зависимостей. Он также умешает количество данных, восстанавливаемых при каждом рендере.
А если совместить useReducer
с useContext
и Typescript, он становится еще мощнее.
Вот как это происходит на практике:
// Этот код очень громоздкий и его тяжело читать
const BasicComponent = () => {
const [isOpen, setIsOpen] = useState(false);
const [name, setName] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const [id, setid] = useState('');
return (
// ...
)
}
// После рефакторинга он более читабельный, быстрый и в нем больше модулей!
const initialState = {
isOpen: false,
name: '',
isLoading: false,
error: null,
id: ''
}
const reducer = (state, action) => {
switch (action.type) {
case 'setIsOpen':
return { ...state, isOpen: action.payload }
break;
// ...
default:
return state;
}
}
const BetterComponent = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
// ...
)
}
Код становится более оптимизированным и читабельным.
Пользовательские хуки
Иногда при работе с хуками React получается очень сложная логика состояния внутри одного компонента. Настолько сложная, что она задействует множество типов хуков, чтобы выполнить одну цель.
К счастью, с помощью пользовательских хуков React можно объединить сложную логику в один доступный хук. Этот прием может пригодиться при создании форм, переключателей, асинхронном поведении и других случаях, когда в компоненте появляется куча хуков.
В качестве примера рассмотрим пользовательский хук, который переключает объекты из списка. Код приведен ниже:
import { useState } from 'react';
type UseToggle<T> = [T[], (item: any) => void, (items?: T[]) => void];
const useToggle = <T = any>(defaultValues?: T[]): UseToggle<T> => {
const [items, setItems] = useState<T[]>(defaultValues || []);
const toggleItem = (item: any) => {
if (items.includes(item)) {
setItems((prev) => prev.filter((i) => i !== item));
} else {
setItems((prev) => prev.concat(item));
}
};
const reset = (newItems?: T[]) => setItems(newItems || []);
return [items, toggleItem, reset];
};
export default useToggle;
Собирая всю логику в пользовательском хуке, код становится чистым и его можно еще раз задействовать в дальнейшем.
Управление глобальным состоянием
В большинстве случаев состояние управляется без внешней библиотеки. В основном её подключают только в крупных приложениях, которые взаимодействуют со сложными состояниями.
Однако и в этом случае, можно воспользоваться встроенным Context API для разделения данных между компонентами.
Если же вы решили, что для управления состоянием необходимо внешнее решение, стоит рассмотреть Recoil — очень легкий и простой инструмент для работы с глобальным состоянием. Для этого также подойдет популярная библиотека Redux. Есть огромное множество материалов о том, как эффективно применять эти инструменты, поэтому не будем затрагивать их в этой статье.
Библиотеки для выборки данных
Может показаться, что данные, полученные из внешних API, не создают больших проблем. Однако все значительно усложняется, когда необходимо их кэшировать (для сокращения количества вызовов API), обновлять и предоставлять им доступ во различные места.
К счастью, существуют библиотеки для управления данными, например React Query. Она помогает извлекать, кэшировать, аннулировать и обновлять данные из внешних источников. Кроме того, эти библиотеки можно использовать для отправки данных внешним клиентам и оптимизации всего рабочего процесса с сервером.
Некоторые библиотеки, например Apollo Client, охватывают управление состоянием, чтобы обработать весь процесс выборки данных и их кэширования, а также автоматического обновления UI более предсказуемым, последовательным и читабельным образом.
Заключение
Управление состоянием в React бывает сложным, но благодаря этим советам, вы можете сделать этот процесс продуктивным и легким для чтения.
Читайте также:
- Как сделать приложение с дополненной реальностью, используя React Native
- Управляйте приложением React с помощью голоса
- Как добавить простую функцию поиска в приложение на React без сервера
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Caelin Sutch: 3 Ways To Handle State Better in React