Skip to main content

Що таке "Container-Presentational Pattern"?

Суть патерну

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 знає як це показати.

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

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

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