Содержание
- Введение
- Что такое «состояние»?
- Преимущества глобального состояния
- Недостатки глобального состояния
- Преимущества разделяемого состояния
- Недостатки разделяемого состояния
- Как разделять состояние?
- Шаблоны и библиотеки управления состоянием
Введение
В последние годы я участвовал в разных проектах, связанных с данными.
Таблицы, социальные субъекты, диаграммы — у всего в интернете имеются данные и способ взаимодействия с ними.
А мы, как разработчики, постоянно ищем способы эффективнее управлять взаимодействиями, чтобы не приходилось принимать лекарства от головной боли, вызываемой всеми этими рассуждениями и отладкой.
Появилось много решений, код стал пригоднее для повторного использования, абстрагированнее. От вопроса «Как справиться с этим сценарием?» мы перешли к «В какой библиотеке имеется все для проекта?».
Из-за обилия вариантов главная проблема сейчас — выявление лучшей библиотеки, а о самих решаемых проблемах часто забывают.
Особенно это относится к React. В управлении состоянием здесь наблюдается эволюция, ведь изначально мало с чем можно работать: недостатки одной библиотеки пытаются решить в другой, одна очень медленная, а другая быстрая, но ей не хватает функционала и т. д. Изучать их можно бесконечно.
Почему бы не внедрить для всех проектов универсальное решение и придерживаться его? Ни одной компании этого не удалось. В каждой ситуации так много отличий и подходов, что практически невозможно найти идеальный инструментарий, который всегда будет лучшим решением.
Проведем аналогию: в перевозке груза фура эффективнее спорткара (тому требуется больше ходок). Если же цель — просто добраться налегке до места назначения, спорткар быстрее.
Очевидно, различия в мире ПО немного сглаживаются: компьютеры и телефоны достаточно быстры, чтобы большинство решений, за исключением некоторых ситуаций, воспринимались конечным пользователем одинаково. Стоит ли остановиться на одном варианте швейцарского ножа и перестать изучать новые? Да, если он помогает выполнить задачу.
Но мы пойдем до конца, поэкспериментируем и разберемся: зачем в React управление состоянием и какая проблема им решается, а также нужна ли продвинутая библиотека, чтобы структурировать код, или инструментов React достаточно для комфортной работы.
Начнем с основ, реализуя решения проблемы разными библиотеками управления состоянием.
Что такое «состояние»?
Состояние — это любая информация, запоминаемая для работы приложения/системы.
Состояние бывает локальным, когда находится в компоненте и потребляется им, или разделяемым, когда один экземпляр потребляется несколькими компонентами.
Состояние находится на сервере (приложения типа crud) или в клиенте (веб-редакторы).
В целом, локальное состояние — это хорошо. Если информация «живет и умирает», где используется, то легко понять, для чего она, если можно ее очистить или реорганизовать.
Разделяемое состояние хранится глобально или в ближайшем общем предке. Поместив его в другое место, получим спагетти-код.
У обоих решений имеются сильные и слабые стороны.
Преимущества глобального состояния
- Всегда доступно: остается весь сеанс и применяется в каждом компоненте.
- Не нужно думать, куда поместить новую информацию для сохранения.
- Требуется меньше рефакторинга: без перемещения вверх-вниз при внедрении новых функций.
- Легко сохраняется/инициализируется «с холода».
Недостатки глобального состояния
- Остается весь сеанс, способно сильно снизить производительность, особенно если неизменяемое.
- Сбивает с толку: зачем здесь эти данные, применяются ли для новой функции и какие компоненты от этого зависят?
- Не очень хорошо масштабируется: в приложении загружается больше данных. Если не очистить ненужную часть, это отразится на производительности.
- Затрудняется присвоение имен: в них должна присутствовать область видимости.
Преимущества разделяемого состояния
- Проще присвоение имен: с помощью локальности дается много контекста.
- Безопаснее удаление и рефакторинг: случаи использования очень близки, поэтому за ними легко следить.
- Удобнее сопровождение: легче понять, для чего оно нужно, если остается близким к случаям использования.
- Довольно хорошо масштабируется: при размонтировании компонентов состояние очищается.
Недостатки разделяемого состояния
- Код в компонентах значительно удлиняется: можно сократить, переместив логику в хук.
- Похожие локальные имена в разных компонентах чреваты путаницей. Решение: поиск и замена на несвязанные варианты.
- Требуется много рефакторинга: перемещение вверх-вниз — это мучение.
- Пробрасывание свойств.
Как разделять состояние?
Не разделять состояние, которое в этом не нуждается, — подход вовсе не плохой. А как насчет того, чтобы поделиться информацией?
Подъем состояния
- По возможности сохраняйте состояние локальным.
- Прямое отслеживание.
- Пробрасывание свойств.
Контекст
- Пробрасывание свойств исключается.
- Осторожнее с провайдерами.
- Может быть глобальным.
- Эффективные повторные отрисовки: при изменении состояния компонентов отрисовываются только те, которыми потребляется контекст.
- Сложно отслеживать/сопровождать: у кого при изменении чего-либо вызывается этот цикл отрисовки?
Внешние библиотеки
- Скрывают сложность.
- Могут быть платформенно-независимыми.
- Или предназначенными для React: использовать соответствующие API для интеграции и/или производительности.
Внешние сущности (ручная реализация с API-интерфейсами, отличными от React, например localstorage и url)
- Синхронизация вкладок и окон.
- Разделяйте состояние отправлением ссылки, например отфильтрованные поиски.
Шаблоны и библиотеки управления состоянием
Возможно, список неполный: постоянно появляются новые.
Для состояния клиента
- Предсказуемая.
- Легко отслеживать, почему, когда и как обновлено состояние.
- Централизованная.
- Шаблонный код.
- Платформенно-независимая.
- Минималистичная: без шаблонного кода.
- Реактивная.
- Асинхронность без усилий.
- С прокси-сервером.
- Платформенно-независимая.
- Простые API.
- Встроенная асинхронность.
- Минималистичная: без шаблонного кода.
- С поддержкой API-интерфейсов React.
- Упрощенная версия Recoil: в четыре раза меньше.
- Несколько ограничена: нет React Fast Refresh и снимков.
- Стабильные API-интерфейсы постоянно хранимого состояния.
- Встроенная асинхронность.
- Централизованная.
- С прокси-сервером.
- Состояние изменяется напрямую.
- Интегрированный ESLint-плагин.
- Платформенно-независимая.
- Шаблонный код: привязки React.
- Платформенно-независимая.
- Потоки как состояние.
- Много теории для освоения.
- Реализация Redux.
- Шаблонный код сведен к минимуму.
- Очень маленькая.
- Сложная типизация: нетривиальным структурам требуется приведение типов.
- Геттеры и сеттеры, напоминает Java.
- Имена полей в состояниях конфликтуют с API, например к
myState.value
нужно обращаться какmyState.nested.value.get()
. - Структура состояния очень легко отслеживается, быстро пишется.
- Прокси-магия, но более явная.
- Используется RxJS.
- Хранилища на основе сущностей.
- С интерфейсом командной строки.
- Шаблонный код: определение репозиториев.
- База данных CRM: как стандартные операции.
- Платформенно-независимая.
Примечание: xState нет в списке, так как она предназначена не для разделения состояния между компонентами, а только для обработки сложных поведений.
Как выбрать правильную, лучшую библиотеку?
Такой не существует. Сформулируем так: лучшую для чего? Даже на этот вопрос может не быть универсального, научного ответа.
Читайте также:
- Cначала Vue, потом React: совет начинающим разработчикам
- Как использовать шаблон проектирования “Адаптер” в React
- 7 расширений VS Code, которые стоит знать разработчику React
Читайте нас в Telegram, VK и Дзен
Перевод статьи Fabio Brunori: State Management in React — Overview