Skip to main content

Що таке "Smart" і "Dumb" компоненти?

Суть патерна

Container-Presentational Pattern ділить компоненти на два типи:

ТипПризначення
Container (контейнер)Відповідає за логіку, дані і стан
Presentational (презентаційний)Відповідає тільки за відображення UI

Ідея: "контейнер думає, а презентаційний показує"


Приклад

Presentational Component

Він отримує дані через props і просто їх відображає.

javascript
function UserCard({ name, age }) { return ( <div className="card"> <h2>{name}</h2> <p>Вік: {age}</p> </div> ); }

Не містить стану Не робить запитів Не знає, звідки приходять дані -> чистий UI-компонент


Container Component

Він керує станом і логікою, і передає дані вниз.

javascript
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 можна замінити без зміни бізнес-логіки

Архітектурно

javascript
Container (логіка) └── Presentational (UI)

Наприклад:

javascript
UserListContainer └── UserList └── UserCard

Типові ознаки

ОзнакаContainerPresentational
Тримає станТакНі
Використовує хуки (useState, useEffect)ТакРідко
Робить запити до APIТакНі
Знає про бізнес-логікуТакНі
Приймає props для відображенняТакТак
Визначає верстку і стиліНіТак

Приклад у сучасній архітектурі (React + Redux)

javascript
// 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> ); }
javascript
// 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 (презентаційний)

Просто отримує дані і рендерить їх.

javascript
function UserCard({ name, age }) { return ( <div className="card"> <h2>{name}</h2> <p>Вік: {age}</p> </div> ); }

Особливості:

  • Не має стану (useState, useEffect)
  • Не знає, звідки прийшли дані
  • Легко тестувати і повторно використовувати
  • Залежить лише від props

Smart Component (контейнер)

Відповідає за бізнес-логіку і дані.

javascript
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, ProvidersButtons, Cards, Modals

Зв'язок між ними

javascript
Smart └── Dumb └── (ще дрібніші Dumb)

Розумний компонент керує потоком даних, а "глупі" відповідають за чистий UI.


Чому це зручно

Код чистіший: логіка не перемішана з версткою Легше тестувати UI окремо UI-компоненти стають придатними для повторного використання Можна змінювати дизайн без зміни логіки Можна використовувати ті самі Dumb-компоненти в різних частинах застосунку


Сучасна еволюція

Сьогодні в React (особливо з хуками і Next.js 13+) цей патерн часто реалізується не буквально як "Smart/Dumb компоненти", а через розділення на:

  • Hooks (розумні) - useUser(), useTodos(), useCart()
  • UI компоненти (глупі) - UserCard, TodoList, CartItem

Приклад:

javascript
// 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-компоненти

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.