Що таке "Smart" і "Dumb" компоненти?
Суть патерна
Container-Presentational Pattern ділить компоненти на два типи:
| Тип | Призначення |
|---|---|
| Container (контейнер) | Відповідає за логіку, дані і стан |
| Presentational (презентаційний) | Відповідає тільки за відображення UI |
Ідея: "контейнер думає, а презентаційний показує"
Приклад
Presentational Component
Він отримує дані через props і просто їх відображає.
function UserCard({ name, age }) {
return (
<div className="card">
<h2>{name}</h2>
<p>Вік: {age}</p>
</div>
);
}Не містить стану Не робить запитів Не знає, звідки приходять дані -> чистий UI-компонент
Container Component
Він керує станом і логікою, і передає дані вниз.
function UserCardContainer() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(data => setUser(data));
}, []);
if (!user) return <p>Завантаження...</p>;
return <UserCard name={user.name} age={user.age} />;
}Отримує дані Керує станом Викликає побічні ефекти Передає дані в презентаційний компонент
Навіщо це потрібно
| Проблема | Рішення через патерн |
|---|---|
| Логіка і UI змішані в одному компоненті -> складно читати | Розділяємо: один думає, інший показує |
| Важко тестувати і повторно використовувати | Презентаційні легко тестувати і використовувати повторно |
| Потрібно відобразити той самий UI з різними джерелами даних | Можна використати один Presentational, а різні Container |
| При редизайні ламається логіка | UI можна замінити без зміни бізнес-логіки |
Архітектурно
Container (логіка)
└── Presentational (UI)Наприклад:
UserListContainer
└── UserList
└── UserCardТипові ознаки
| Ознака | Container | Presentational |
|---|---|---|
| Тримає стан | Так | Ні |
Використовує хуки (useState, useEffect) | Так | Рідко |
| Робить запити до API | Так | Ні |
| Знає про бізнес-логіку | Так | Ні |
| Приймає props для відображення | Так | Так |
| Визначає верстку і стилі | Ні | Так |
Приклад у сучасній архітектурі (React + Redux)
// Presentational.jsx
export function TodoList({ todos, onToggle }) {
return (
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => onToggle(todo.id)}
style={{ textDecoration: todo.done ? 'line-through' : 'none' }}
>
{todo.text}
</li>
))}
</ul>
);
}// Container.jsx
import { useSelector, useDispatch } from 'react-redux';
import { toggleTodo } from '../store/todoSlice';
import { TodoList } from './Presentational';
export function TodoListContainer() {
const todos = useSelector(state => state.todos);
const dispatch = useDispatch();
return (
<TodoList
todos={todos}
onToggle={(id) => dispatch(toggleTodo(id))}
/>
);
}У сучасному React
Хоч патерн родом з епохи класових компонентів, він все ще актуальний, просто реалізується через хуки і композицію.
Зараз "контейнером" може бути:
- хук (
useUser,useTodos) - компонент-обгортка
- контекст-провайдер
Підсумок
| Що | Опис |
|---|---|
| Ідея | Розділити "логіку" і "відображення" |
| Container | Отримує й обробляє дані |
| Presentational | Показує інтерфейс |
| Користь | Повторне використання, читабельність, тестованість |
| Сучасний аналог | Хуки + Dumb/UI компоненти |
Підсумкова формула:
Containerзнає що показати,Presentationalзнає як це показати.
Поняття "Smart" і "Dumb" компонентів (розумні й глупі) - це більш неформальна, але дуже популярна версія патерна "Container-Presentational", про яку ти щойно запитував.
Розберемося покроково.
Суть ідеї
React-застосунки складаються з двох типів компонентів:
| Тип компонента | Що робить |
|---|---|
| Smart (розумний) | Керує логікою, станом, запитами і даними |
| Dumb (глупий) | Відповідає лише за відображення (UI), не "думає" |
"Smart thinks, Dumb shows" - розумний думає, глупий показує.
Приклад
Dumb Component (презентаційний)
Просто отримує дані і рендерить їх.
function UserCard({ name, age }) {
return (
<div className="card">
<h2>{name}</h2>
<p>Вік: {age}</p>
</div>
);
}Особливості:
- Не має стану (
useState,useEffect) - Не знає, звідки прийшли дані
- Легко тестувати і повторно використовувати
- Залежить лише від
props
Smart Component (контейнер)
Відповідає за бізнес-логіку і дані.
function UserContainer() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(data => setUser(data));
}, []);
if (!user) return <p>Завантаження...</p>;
return <UserCard name={user.name} age={user.age} />;
}Особливості:
- Керує станом і логікою
- Робить запити до API
- Обробляє події
- Передає дані вниз через props
Відмінності в таблиці
| Характеристика | Smart компонент | Dumb компонент |
|---|---|---|
| Керує станом | Так | Ні |
| Робить запити | Так | Ні |
| Знає бізнес-логіку | Так | Ні |
| Рендерить UI | Частково | Основне |
| Приймає props | Так | Так |
| Придатний для повторного використання | Не завжди | Легко |
| Тестується | Складніше | Просто |
| Приклади | Containers, Hooks, Providers | Buttons, Cards, Modals |
Зв'язок між ними
Smart
└── Dumb
└── (ще дрібніші Dumb)Розумний компонент керує потоком даних, а "глупі" відповідають за чистий UI.
Чому це зручно
Код чистіший: логіка не перемішана з версткою Легше тестувати UI окремо UI-компоненти стають придатними для повторного використання Можна змінювати дизайн без зміни логіки Можна використовувати ті самі Dumb-компоненти в різних частинах застосунку
Сучасна еволюція
Сьогодні в React (особливо з хуками і Next.js 13+) цей патерн часто реалізується не буквально як "Smart/Dumb компоненти", а через розділення на:
- Hooks (розумні) -
useUser(),useTodos(),useCart() - UI компоненти (глупі) -
UserCard,TodoList,CartItem
Приклад:
// useUser.js
export function useUser() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(r => r.json())
.then(setUser);
}, []);
return user;
}
// UserCard.jsx
export function UserCard({ user }) {
return (
<div>{user?.name ?? 'Завантаження...'}</div>
);
}
// Page.jsx
import { useUser } from './useUser';
import { UserCard } from './UserCard';
export default function Page() {
const user = useUser();
return <UserCard user={user} />;
}Тепер "розум" знаходиться в хуку, а "глупість" - в UI-компоненті. Це сучасний спосіб реалізувати той самий патерн.
Підсумок
| Поняття | Що означає |
|---|---|
| Smart Component | Компонент, який керує логікою, станом і даними |
| Dumb Component | Компонент, який просто відображає UI на основі props |
| Патерн вирішує | Розділення відповідальності і покращення архітектури |
| Сучасний аналог | Хуки + UI-компоненти |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.