React исполнилось 13 лет — первый релиз состоялся 29 мая 2013 года.
Я использую React с 2017 года для создания самых разных приложений. За это время успел поработать как с проектами, которые проектировал сам, так и с теми, которые достались в наследство.
Сразу оговорюсь: тут не будет технических инсайдов или рассказов про новые API. Скорее это набор выводов и наблюдений, которые накопились за почти 10 лет работы.
React сегодня кажется есть везде, где присутствует фронтенд. Веб-приложения, терминалы, 3D-сцены, аудио-интерфейсы — экосистема давно вышла далеко за пределы браузерных страниц.
Главная идея React при этом остается неизменной: из простых компонентов собирать более сложные системы. Концепция выглядит простой, но именно вокруг нее возникает большинство архитектурных проблем.
Не случайно существует статья Thinking in React. Многие команды читают документацию по API, но пропускают сам подход к проектированию интерфейсов. В проектах, которые мне приходилось поддерживать, основные сложности обычно возникали именно из-за этого. Появлялись чрезмерно сложные компоненты, неудобные API, неожиданные побочные эффекты и баги, связанные с ререндерами.
Отдельная проблема — структура проекта. Часто все компоненты складываются в одну папку независимо от назначения: общие, доменные, виджеты, страницы. Со временем навигация по такому проекту становится сложнее, а границы ответственности размываются.
Несколько принципов, которые я для себя вынес за эти годы.
Один файл — один компонент. То же касается функций и констант. Такой подход упрощает навигацию, улучшает переиспользование и помогает инструментам сборки эффективнее работать с tree shaking. Линтеры на архитектурные границы тоже будет проще настроить и этим жанглировать.
Используйте композицию и слоты. Компонент должен предоставлять точки расширения, а не пытаться предусмотреть все варианты использования заранее.
Проектируйте API компонентов через поведение, а не через место использования. Когда в компоненте появляются пропсы вроде isAdmin, isMobile или другие флаги, описывающие контекст использования, это часто сигнал того, что ответственность оказалась не на своем месте. Решение о том, какой сценарий нужен, должно приниматься снаружи. Компоненту лучше сообщать, что делать, а не где он находится.
Должно получиться что-то "Я вставил компоненты из витрины, и он работает, а теперь докручу изменениями пропсов его вид"
Не бойтесь копировать композицию компонентов, если это делает код понятнее. Поддерживать несколько похожих сценариев зачастую проще, чем разбираться в большом универсальном компоненте с множеством условных веток. Раньше такой подход действительно вызывал вопросы о поддерживаемости. Сегодня рефакторинг через AST-кодмоды, автоматизацию и ИИ-инструменты заметно снижает стоимость подобных изменений описывая их на естественном языке.
Создавайте локальный state только для логики интерфейса. Не стоит превращать каждый компонент в хранилище бизнес-логики.
Используйте Context там, где его действительно сильные стороны раскрываются. Например, когда значение может переопределяться ниже по дереву компонентов и менять поведение вложенных элементов. Особенно полезно это бывает в рекурсивных компонентах.
Читайте раздел Escape Hatches на react.dev. Многие спорные решения уже подробно разобраны авторами React, и понимание этих ограничений помогает избежать архитектурных ошибок.
Общие компоненты стоит выносить за пределы конкретного приложения: в UI Kit пакет, воркспейс или монорепозиторий. Внутри самого приложения основной фокус должен оставаться на доменной модели и бизнес-задачах.
И последнее — следите за экосистемой и обновляйте зависимости вовремя.
Откладывать обновления удобно только в краткосрочной перспективе. Со временем накапливается технический долг, а очередное обновление React, библиотеки из стека или экосистемы начинает требовать обновления TypeScript, сборщика (переход на ESM), инфраструктуры и прикладного кода одновременно. В результате простая задача превращается в технические релизы.