Нескольких страниц, пара запросов к API, простейший стейт — с этим может справиться любой профессионал. Потом ещё пара страниц, немного логики, пара новых хуков. Переключатель языка. Тёмная тема. Мобильная версия. И вот уже номера строк в файлах компонентов становятся четырёхзначными. Код усложняется, появляются ошибки. В этой статье Дмитрий Радковский, эксперт разработки 2web и 3web платформ, рассказал, как организовать React-компоненты так, чтобы проект мог легко пережить проблему бурного роста.
Зачем
В большинстве проектов в процессе развития возникают одни и те же потребности:
Для удовлетворения этих потребностей удобно работать с базой компонентов, разбитой по слоям, где каждый слой берёт на себя Single Responsibility и взаимодействует исключительно с интерфейсом нижнего слоя.
С выходом React Hooks и React Contexts появилась возможность изолировать компоненты в независимые ветки дерева, не коммитясь на конкретную архитектуру приложения раньше времени.
Условия
Состояние (стейт) приложения
Организация компонентов не должна диктовать использование того или иного подхода к управлению стейтом приложения. У разработчиков может быть масса причин использовать определённую библиотеку управления стейтом, такая возможность должна оставаться.
Использование в легаси
Невозможно предугадать все возможные будущие проблемы на старте проекта, поэтому организация компонентов может быть отложена на более поздний этап. Мы принимаем за данность, что в проекте будет существовать огромный пласт легаси-кода, который должен сосуществовать с более упорядоченным, и переезд будет осуществляться постепенно в рамках решения бизнес-задач.
Эффективность
Организация компонентов обязана уменьшать когнитивную нагрузку при работе с кодом, а не увеличивать её. Бойлерплейт должен быть минимальным, написание хорошо организованного кода не должно быть медленнее, чем написание аналогичного кода в беспорядке.
Слои
В этой статье я описываю разбиение на три слоя компонентов:
View-компоненты
Компоненты уровня презентации («глупые» компоненты, View-компоненты).
Признаки View-компонентов:
View-компоненты НЕ могут:
Примеры
Простая кнопка с прокидыванием цвета через пропсы
Простая кнопка определённого цвета
Сложный составной экран без логики
Подложка под попап без логики и содержимого
Container-компоненты
Компоненты уровня логики («умные» компоненты, Container-компоненты).
Признаки Container-компонентов:
Container-компоненты НЕ могут:
Примеры
Экран пэйвола с глобальной локализацией и форматированием числа
Подгружающийся список
Global-компоненты
Компоненты глобального уровня («глобальные» компоненты, Global-компоненты).
Признаки Global-компонентов:
Global-компоненты НЕ могут:
Примеры
Окно оплаты с вызовом глобальной функции
Главный экран приложения на основе авторизации юзера
Заключение
Набор слоёв может быть и другим в зависимости от процесса разработки в вашей команде, но важно соблюдать иерархию и не позволять компонентам перепрыгивать слои и брать на себя смешанную ответственность.
Распределение компонентов по слоям позволяет более точечно распределить ответственность внутри команды и поднять автономность:
Такой подход уменьшает оверхед на коммуникацию в команде, что особенно важно в географически распределённых командах. Кроме того, снижается риск конфликтов в системе контроля версий, что тоже экономит время на решение конфликтов и мердж веток.