Как организовать структуру React-проекта: папки и соглашения
Практика3 минРедакция Innovialabs
Коротко
Для небольших проектов достаточно группировки по типам файлов, а растущее приложение лучше делить по фичам: всё, что относится к одной функции, лежит в одной папке, а общий код — в shared.
Короткий ответ
У React нет обязательной структуры, поэтому решение остаётся за командой. Работающее правило: маленький проект — группировка по типам, растущий — по фичам. Главное — чтобы любой разработчик за минуту понял, где искать код и куда класть новый.
По типам или по фичам
По типам (type-based) — все компоненты в components/, все хуки в hooks/, все запросы в api/.
По фичам (feature-based) — код группируется по функциям продукта: auth/, cart/, orders/. Внутри фичи лежат её компоненты, хуки, запросы и типы.
| Критерий | По типам | По фичам |
|---|---|---|
| Порог входа | Низкий, понятно сразу | Нужно договориться о границах фич |
| Рост проекта | Папки разрастаются до сотен файлов | Каждая фича остаётся компактной |
| Удаление функции | Файлы разбросаны по проекту | Удаляется одна папка |
| Работа команды | Частые конфликты в общих папках | Команды работают в своих фичах |
Масштабируемое дерево папок
src/
app/ # точка входа, роутинг, провайдеры
pages/ # страницы, собирают фичи
features/
cart/
components/
hooks/
api.ts
types.ts
index.ts # публичный интерфейс фичи
auth/
shared/
ui/ # Button, Modal, Input
lib/ # утилиты, форматирование дат
api/ # HTTP-клиент, базовая настройка
config/
Если вы используете фреймворк вроде Next.js, папку app/ или pages/ задаёт его роутинг. Тогда держите в ней только маршруты и тонкие страницы, а логику — в features/ и shared/.
Правила, которые держат структуру в порядке
- Зависимости идут в одну сторону:
pages→features→shared. Модуль изsharedне импортирует фичи. - Фичи не лезут друг в друга напрямую. Если
ordersнужен код изcart, импортируйте черезfeatures/cart/index.ts, а не из внутренних файлов. - Код живёт рядом с местом использования. Хук, нужный одному компоненту, лежит рядом с ним. В
sharedпереносите только то, что реально используется в нескольких местах. - Неглубокая вложенность. Больше трёх-четырёх уровней папок обычно означает, что структура переусложнена.
Соглашения об именах
- Компоненты — PascalCase:
ProductCard.tsx. Одна папка на компонент, если у него есть стили, тесты и подкомпоненты. - Хуки — с префиксом
use:useCart.ts. - Утилиты и прочие модули — camelCase или kebab-case; выберите один стиль и закрепите его в линтере.
- Тесты — рядом с файлом:
ProductCard.test.tsx. - Алиасы импорта вроде
@/shared/uiвместо../../../shared/ui.
Общий UI
shared/ui — это кирпичики интерфейса без бизнес-логики: кнопки, поля, модальные окна, типографика. Они не знают о корзине или заказах и получают всё через пропсы. Компонент, который знает о предметной области (например, CartItem), относится к фиче.
Где держать API-логику
Не вызывайте fetch прямо в компонентах. Удобная схема из трёх слоёв:
shared/api— настроенный HTTP-клиент: базовый URL, заголовки, обработка ошибок.features/*/api.ts— функции запросов фичи:getCart(),addToCart().- Хуки фичи — оборачивают запросы, например через TanStack Query, и отдают компонентам данные и статусы.
Так компонент отвечает только за отображение, а смена API затрагивает один слой.
Типичные ошибки
- Папка
utils/илиhelpers/, куда складывают всё подряд. - Преждевременное дробление: десять папок для проекта из пяти компонентов.
- Циклические импорты между фичами.
- Разные соглашения в разных частях проекта без записанных правил.