- Удалён shiki (9.5→0 МБ), создан regex-токенизатор для html/css/xml - CLI переведён с аргументов на конфиг-файл svg-sprites.config.ts - Превью переработано: React-приложение вместо инлайн HTML - Добавлен футер с названием пакета и ссылкой на репозиторий - Исправлена загрузка dev-data.js для Vite 8 - Футер прижат к низу, содержимое центрировано
119 lines
5.1 KiB
Markdown
119 lines
5.1 KiB
Markdown
---
|
||
title: Компоненты
|
||
scope: applied
|
||
keywords: [компонент, props, jsx, ui, clsx, cl, React, FC]
|
||
when: "Создание или редактирование React-компонентов: структура, пропсы, стили"
|
||
---
|
||
# Компоненты
|
||
|
||
Правила написания React-компонентов: файловая структура модуля, типизация пропсов, документирование и реализация. Раздел охватывает компоненты всех слоёв — от `shared/ui` до `screens`.
|
||
|
||
Архитектурные слои и их назначение описаны в разделе [Архитектура](/basics/architecture).
|
||
|
||
|
||
## Правила организации
|
||
|
||
1. Один компонент — один файл.
|
||
2. Компонент не содержит бизнес-логики — логика и сайд-эффекты выносятся в хуки или сторы.
|
||
3. Дочерние компоненты размещаются в сегменте `ui/` и подчиняются тем же правилам структуры.
|
||
4. Публичный API модуля — только `index.ts`. Прямые импорты внутренних файлов запрещены.
|
||
|
||
## Базовая структура компонента
|
||
|
||
Минимальный набор файлов: компонент, стили, типы и публичный экспорт.
|
||
|
||
```text
|
||
container/
|
||
├── styles/
|
||
│ └── container.module.css
|
||
├── types/
|
||
│ └── container.type.ts
|
||
├── container.ui.tsx
|
||
└── index.ts
|
||
```
|
||
|
||
## Именования
|
||
|
||
- Имя корневого css класса всегда `.root`
|
||
- Тип пропсов именуется `{ComponentName}Props`.
|
||
- Тип пользовательских параметров именуется `{ComponentName}Params`.
|
||
|
||
## Типизация
|
||
|
||
Структура типов компонента показана в [примере](#пример). Ниже — обоснования ключевых решений.
|
||
|
||
- **`type` вместо `interface`** — гибче для пропсов: поддерживает union, intersection, mapped types. Declaration merging пропсам не нужно.
|
||
- **Без `FC`** — неявно добавляет `children`, усложняет дженерики, не даёт преимуществ перед аннотацией параметра.
|
||
- **Типы в `types/`, а не в `.tsx`** — предотвращает циклические зависимости (компонент импортирует хук, хук импортирует тип из компонента) и разделяет ответственность: `.tsx` для рендера, `.type.ts` для данных.
|
||
- **Без возвращаемого типа** — TypeScript выводит из JSX. Осознанное исключение из [базового правила](/basics/typing).
|
||
|
||
## Реализация
|
||
|
||
- Пропсы деструктурируются в теле компонента, не в параметрах.
|
||
- Порядок: пользовательские → системные (`children`, `className`) → `...htmlAttr`.
|
||
- `className` объединяется с корневым классом через `cl()`: `cl(styles.root, className)`.
|
||
- `...htmlAttr` прокидывается на корневой элемент.
|
||
|
||
## Пример
|
||
|
||
`container/types/container.type.ts`
|
||
|
||
```ts
|
||
import type { HTMLAttributes } from 'react'
|
||
|
||
/**
|
||
* Параметры компонента Container.
|
||
*/
|
||
export type ContainerParams = {}
|
||
|
||
/** HTML-атрибуты корневого элемента. */
|
||
type RootAttrs = HTMLAttributes<HTMLDivElement>
|
||
|
||
export type ContainerProps = RootAttrs & ContainerParams
|
||
```
|
||
|
||
`container/styles/container.module.css`
|
||
|
||
```css
|
||
.root {
|
||
max-width: var(--content-width);
|
||
margin: 0 auto;
|
||
padding: 0 var(--spacing-4);
|
||
}
|
||
```
|
||
|
||
`container/container.ui.tsx`
|
||
|
||
```tsx
|
||
import cl from 'clsx'
|
||
import type { ContainerProps } from './types/container.type'
|
||
import styles from './styles/container.module.css'
|
||
|
||
/**
|
||
* Контейнер с адаптивной максимальной шириной.
|
||
*
|
||
* Используется для:
|
||
* - обёртки контента страниц с ограничением ширины
|
||
* - центрирования блоков в лейауте
|
||
*/
|
||
export const Container = (props: ContainerProps) => {
|
||
const { children, className, ...htmlAttr } = props
|
||
|
||
return (
|
||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||
{children}
|
||
</div>
|
||
)
|
||
}
|
||
```
|
||
|
||
`container/index.ts`
|
||
|
||
```ts
|
||
export { Container } from './container.ui'
|
||
```
|
||
|
||
## Дочерние компоненты
|
||
|
||
Если модулю нужны внутренние подкомпоненты — генерировать их из шаблона `component` в папку `ui/` внутри родительского модуля. Дочерние компоненты не экспортируются через `index.ts` родителя.
|