Управление состоянием в React: обзор



Книга Управление состоянием в React: обзор



Содержание



  • Введение

  • Что такое «состояние»?

  • Преимущества глобального состояния

  • Недостатки глобального состояния

  • Преимущества разделяемого состояния

  • Недостатки разделяемого состояния

  • Как разделять состояние?

  • Шаблоны и библиотеки управления состоянием


Введение


В последние годы я участвовал в разных проектах, связанных с данными.





Таблицы, социальные субъекты, диаграммы  —  у всего в интернете имеются данные и способ взаимодействия с ними.


А мы, как разработчики, постоянно ищем способы эффективнее управлять взаимодействиями, чтобы не приходилось принимать лекарства от головной боли, вызываемой всеми этими рассуждениями и отладкой.


Появилось много решений, код стал пригоднее для повторного использования, абстрагированнее. От вопроса «Как справиться с этим сценарием?» мы перешли к «В какой библиотеке имеется все для проекта?».


Из-за обилия вариантов главная проблема сейчас  —  выявление лучшей библиотеки, а о самих решаемых проблемах часто забывают.


Особенно это относится к React. В управлении состоянием здесь наблюдается эволюция, ведь изначально мало с чем можно работать: недостатки одной библиотеки пытаются решить в другой, одна очень медленная, а другая быстрая, но ей не хватает функционала и т. д. Изучать их можно бесконечно.


Почему бы не внедрить для всех проектов универсальное решение и придерживаться его? Ни одной компании этого не удалось. В каждой ситуации так много отличий и подходов, что практически невозможно найти идеальный инструментарий, который всегда будет лучшим решением.


Проведем аналогию: в перевозке груза фура эффективнее спорткара (тому требуется больше ходок). Если же цель  —  просто добраться налегке до места назначения, спорткар быстрее.


Очевидно, различия в мире ПО немного сглаживаются: компьютеры и телефоны достаточно быстры, чтобы большинство решений, за исключением некоторых ситуаций, воспринимались конечным пользователем одинаково. Стоит ли остановиться на одном варианте швейцарского ножа и перестать изучать новые? Да, если он помогает выполнить задачу.


Но мы пойдем до конца, поэкспериментируем и разберемся: зачем в React управление состоянием и какая проблема им решается, а также нужна ли продвинутая библиотека, чтобы структурировать код, или инструментов React достаточно для комфортной работы.


Начнем с основ, реализуя решения проблемы разными библиотеками управления состоянием.




Что такое «состояние»?



Состояние  —  это любая информация, запоминаемая для работы приложения/системы.



Состояние бывает локальным, когда находится в компоненте и потребляется им, или разделяемым, когда один экземпляр потребляется несколькими компонентами.


Состояние находится на сервере (приложения типа crud) или в клиенте (веб-редакторы).





В целом, локальное состояние  —  это хорошо. Если информация «живет и умирает», где используется, то легко понять, для чего она, если можно ее очистить или реорганизовать.


Разделяемое состояние хранится глобально или в ближайшем общем предке. Поместив его в другое место, получим спагетти-код.


У обоих решений имеются сильные и слабые стороны.


Преимущества глобального состояния



  • Всегда доступно: остается весь сеанс и применяется в каждом компоненте.

  • Не нужно думать, куда поместить новую информацию для сохранения.

  • Требуется меньше рефакторинга: без перемещения вверх-вниз при внедрении новых функций.

  • Легко сохраняется/инициализируется «с холода».


Недостатки глобального состояния



  • Остается весь сеанс, способно сильно снизить производительность, особенно если неизменяемое.

  • Сбивает с толку: зачем здесь эти данные, применяются ли для новой функции и какие компоненты от этого зависят?

  • Не очень хорошо масштабируется: в приложении загружается больше данных. Если не очистить ненужную часть, это отразится на производительности.

  • Затрудняется присвоение имен: в них должна присутствовать область видимости.


Преимущества разделяемого состояния



  • Проще присвоение имен: с помощью локальности дается много контекста.

  • Безопаснее удаление и рефакторинг: случаи использования очень близки, поэтому за ними легко следить.

  • Удобнее сопровождение: легче понять, для чего оно нужно, если остается близким к случаям использования.

  • Довольно хорошо масштабируется: при размонтировании компонентов состояние очищается.


Недостатки разделяемого состояния



  • Код в компонентах значительно удлиняется: можно сократить, переместив логику в хук.

  • Похожие локальные имена в разных компонентах чреваты путаницей. Решение: поиск и замена на несвязанные варианты.

  • Требуется много рефакторинга: перемещение вверх-вниз  —  это мучение.

  • Пробрасывание свойств.


Как разделять состояние?


Не разделять состояние, которое в этом не нуждается,  —  подход вовсе не плохой. А как насчет того, чтобы поделиться информацией?


Подъем состояния



  • По возможности сохраняйте состояние локальным.

  • Прямое отслеживание.

  • Пробрасывание свойств.


Контекст



  • Пробрасывание свойств исключается.

  • Осторожнее с провайдерами.

  • Может быть глобальным.

  • Эффективные повторные отрисовки: при изменении состояния компонентов отрисовываются только те, которыми потребляется контекст.

  • Сложно отслеживать/сопровождать: у кого при изменении чего-либо вызывается этот цикл отрисовки?


Внешние библиотеки



  • Скрывают сложность.

  • Могут быть платформенно-независимыми.

  • Или предназначенными для React: использовать соответствующие API для интеграции и/или производительности.


Внешние сущности (ручная реализация с API-интерфейсами, отличными от React, например localstorage и url)



  • Синхронизация вкладок и окон.

  • Разделяйте состояние отправлением ссылки, например отфильтрованные поиски.


Шаблоны и библиотеки управления состоянием


Возможно, список неполный: постоянно появляются новые.


Для состояния клиента


Redux



  • Предсказуемая.

  • Легко отслеживать, почему, когда и как обновлено состояние.

  • Централизованная.

  • Шаблонный код.

  • Платформенно-независимая.


MobX



  • Минималистичная: без шаблонного кода.

  • Реактивная.

  • Асинхронность без усилий.

  • С прокси-сервером.

  • Платформенно-независимая.


Recoil



  • Простые API.

  • Встроенная асинхронность.

  • Минималистичная: без шаблонного кода.

  • С поддержкой API-интерфейсов React.


Jotai



  • Упрощенная версия Recoil: в четыре раза меньше.

  • Несколько ограничена: нет React Fast Refresh и снимков.

  • Стабильные API-интерфейсы постоянно хранимого состояния.


Zustand



  • Встроенная асинхронность.

  • Централизованная.


Valtio



  • С прокси-сервером.

  • Состояние изменяется напрямую.

  • Интегрированный ESLint-плагин.

  • Платформенно-независимая.


RxJS



  • Шаблонный код: привязки React.

  • Платформенно-независимая.

  • Потоки как состояние.

  • Много теории для освоения.


Rematch



  • Реализация Redux.

  • Шаблонный код сведен к минимуму.

  • Очень маленькая.

  • Сложная типизация: нетривиальным структурам требуется приведение типов.


Hookstate



  • Геттеры и сеттеры, напоминает Java.

  • Имена полей в состояниях конфликтуют с API, например к myState.value нужно обращаться как myState.nested.value.get().

  • Структура состояния очень легко отслеживается, быстро пишется.

  • Прокси-магия, но более явная.


A̵k̵i̵t̵a̵ Elf



  • Используется RxJS.

  • Хранилища на основе сущностей.

  • С интерфейсом командной строки.

  • Шаблонный код: определение репозиториев.

  • База данных CRM: как стандартные операции.

  • Платформенно-независимая.


Примечание: xState нет в списке, так как она предназначена не для разделения состояния между компонентами, а только для обработки сложных поведений.




Как выбрать правильную, лучшую библиотеку?


Такой не существует. Сформулируем так: лучшую для чего? Даже на этот вопрос может не быть универсального, научного ответа.



245   0  

Comments

    Ничего не найдено.