What is the "Container-Presentational Pattern"?
The essence of the pattern
The Container-Presentational Pattern splits components into two types:
| Type | Purpose |
|---|---|
| Container | Responsible for logic, data, and state |
| Presentational | Responsible only for rendering the UI |
The idea: "the container thinks, the presentational component shows"
Example
Presentational Component
It receives data via props and simply renders it.
function UserCard({ name, age }) {
return (
<div className="card">
<h2>{name}</h2>
<p>Age: {age}</p>
</div>
);
}Holds no state Makes no requests Doesn't know where the data comes from → a pure UI component
Container Component
It manages state and logic and passes data down.
function UserCardContainer() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(data => setUser(data));
}, []);
if (!user) return <p>Loading...</p>;
return <UserCard name={user.name} age={user.age} />;
}Fetches data Manages state Triggers side effects Passes data into the presentational component
Why this is needed
| Problem | Solution via the pattern |
|---|---|
| Logic and UI are mixed in one component → hard to read | Split it: one thinks, the other shows |
| Hard to test and reuse | Presentational components are easy to test and reuse |
| Need to render the same UI with different data sources | You can use one Presentational with different Containers |
| A redesign breaks the logic | The UI can be replaced without changing the business logic |
Architecturally
Container (logic)
└── Presentational (UI)For example:
UserListContainer
└── UserList
└── UserCardTypical signs
| Sign | Container | Presentational |
|---|---|---|
| Holds state | Yes | No |
Uses hooks (useState, useEffect) | Yes | Rarely |
| Makes API requests | Yes | No |
| Knows about business logic | Yes | No |
| Accepts props for rendering | Yes | Yes |
| Defines markup and styles | No | Yes |
Example in a modern architecture (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))}
/>
);
}In modern React
Although the pattern comes from the era of class components, it is still relevant, just implemented through hooks and composition.
Now the "container" can be:
- a hook (
useUser,useTodos) - a wrapper component
- a context provider
Summary
| What | Description |
|---|---|
| Idea | Separate "logic" from "presentation" |
| Container | Fetches and processes data |
| Presentational | Renders the interface |
| Benefit | Reusability, readability, testability |
| Modern equivalent | Hooks + dumb/UI components |
The final formula:
Containerknows what to show,Presentationalknows how to show it.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.