Компонент: что это такое
Компонент — изолированная, переиспользуемая единица UI: функция (или класс), принимающая props и возвращающая разметку (JSX/HTML) с опциональным поведением и состоянием.
Зачем нужно
Компонентный подход — основа современного фронтенда. Вместо монолитного HTML, где изменение кнопки требует правки в десятках мест, компонент описывает кнопку один раз — и используется везде. Изменение компонента мгновенно применяется всюду. Это даёт переиспользование, изоляцию (баг в одном компоненте не ломает другие) и понятную структуру приложения.
Где используется
- React, Vue, Angular, Svelte — все современные фреймворки строятся на компонентах
- Web Components (нативный стандарт браузера) — custom elements
- React Native — компоненты для мобильных приложений
- Любой UI: от кнопки до целой страницы — всё компонент
Функциональный компонент (React)
// Минимальный компонент — функция, возвращающая JSX
function Greeting({ name }) {
return <h1>Привет, {name}!</h1>;
}
// Использование как HTML-элемент
<Greeting name="Мир" />
Компонент с состоянием и эффектами
import { useState, useEffect } from 'react';
// Компонент инкапсулирует: UI + состояние + поведение
function ProductCard({ productId, onAddToCart }) {
// Состояние — личные данные компонента
const [product, setProduct] = useState(null);
const [isWishlisted, setIsWishlisted] = useState(false);
const [isLoading, setIsLoading] = useState(true);
// Эффект — побочное действие после рендера
useEffect(() => {
fetch(`/api/products/${productId}`)
.then(r => r.json())
.then(data => {
setProduct(data);
setIsLoading(false);
});
}, [productId]);
const handleWishlist = () => setIsWishlisted(prev => !prev);
if (isLoading) return <div className="card-skeleton" />;
// JSX — декларативное описание UI
return (
<article className="product-card">
<img src={product.imageUrl} alt={product.name} />
<h2>{product.name}</h2>
<p className="price">{product.price} ₽</p>
<div className="actions">
<button onClick={ => onAddToCart(product)}>В корзину</button>
<button
onClick={handleWishlist}
aria-pressed={isWishlisted}
className={isWishlisted ? 'wishlisted' : ''}
>
{isWishlisted ? 'Убрать из избранного' : 'В избранное'}
</button>
</div>
</article>
);
}
Композиция компонентов
// Компоненты собираются в дерево — как матрёшки
function App() {
return (
<Layout> {/* Layout содержит Header + main + Footer */}
<Header />
<main>
<ProductGrid> {/* Grid рендерит массив ProductCard */}
{products.map(p => (
<ProductCard
key={p.id}
productId={p.id}
onAddToCart={addToCart}
/>
))}
</ProductGrid>
</main>
<Footer />
</Layout>
);
}
Принципы хорошего компонента
Единственная ответственность — один компонент, одна задача
Переиспользование — работает в разных контекстах
Изоляция — не зависит от глобального состояния без необходимости
Тестируемость — легко протестировать в изоляции
Небольшой размер — до ~150 строк; больше → разбить
Частые ошибки
- Компоненты-монолиты — 500+ строк с логикой, стилями, данными; разбивайте на более мелкие.
- Прямая мутация пропсов —
props.items.push(...)нарушает однонаправленный поток; props иммутабельны. - Логика рендеринга в коллбэках —
onClick={ => { if (condition) setA(1); else setB(2); /* ещё 20 строк */ }}— выносите логику в именованные функции. - Компонент знает слишком много — обращается к глобальному store напрямую вместо получения данных через props.
Связанные темы
- _MOC SPA
- Props -- передача данных
- State -- внутреннее состояние
- Жизненный цикл компонента
- Atomic Design
- Декларативный vs Императивный UI