What is a "container component"?
Short answer
A container component is a component that:
is responsible for logic, data, and state, but is not responsible for the visual appearance (markup).
It usually:
- fetches data (from an API, context, store, etc.);
- manages state (
useState,useEffect); - passes that data to a presentational (UI) component via
props.
The idea behind the split
React components can be roughly divided into two types:
| Type | What it does | Contains |
|---|---|---|
| Presentational (UI) | Responsible for rendering (markup, styles) | JSX |
| Container (smart) | Responsible for logic, data, state | hooks, API, handlers |
Example 1. Basic example
Presentational component:
function UserCard({ name, email }) {
return (
<div className="user-card">
<h3>{name}</h3>
<p>{email}</p>
</div>
);
}This component:
- simply renders data;
- does not know where it came from.
Container component:
function UserContainer() {
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} email={user.email} />;
}This component:
- manages data loading;
- stores state;
- passes the result to
UserCard.
Example 2. Clean separation of responsibility
App
┣ UserContainer (logic)
┗ UserCard (rendering)UserContainer decides what to show,
UserCard decides how it looks.
Example 3. A container can manage several UI components
function ProductsContainer() {
const [products, setProducts] = useState([]);
const [filter, setFilter] = useState("");
useEffect(() => {
fetch("/api/products")
.then(res => res.json())
.then(data => setProducts(data));
}, []);
const filtered = products.filter(p => p.name.includes(filter));
return (
<>
<SearchBar value={filter} onChange={setFilter} />
<ProductList items={filtered} />
</>
);
}Here:
- The container manages data and filtering;
SearchBarandProductListsimply render the UI.
Advantages of the "Container + Presentational" approach
Separation of concerns - logic separate, UI separate
Reusability - UserCard can be used in different places
Testability - UI and logic can be tested separately
Easier maintenance - changes in logic do not break the markup
Improved code readability
Example 4. A generic pattern
// Container
function DataContainer({ render }) {
const [data, setData] = useState([]);
useEffect(() => {
fetch("/api/items")
.then(r => r.json())
.then(setData);
}, []);
return render(data);
}
// Usage
<DataContainer render={(items) => <ItemList items={items} />} />This uses a render prop, but the idea is the same: the container handles the data, and the child component handles the rendering.
When to use container components
Use one when:
- the component needs to load data (API, GraphQL, Firebase);
- you need to store state (
useState,useReducer); - the component manages interaction logic (for example, filters, sorting, a form);
- you want to separate the visual layer from the logical one.
When you don't need one
Don't create a container if:
- the component simply renders UI;
- it has no logic or state;
- the data already arrives ready-made through
props.
Summary
| Component type | Main task | Example |
|---|---|---|
| Container | Logic, state, requests, handlers | UserContainer, ProductsContainer |
| Presentational (UI) | Markup and rendering of data | UserCard, ProductList |
Main idea:
A container component is a "smart" component that manages logic and data, and delegates the visual part to "dumb" (presentational) components.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.