🧭 Introduction
As React applications grow, components start doing too much:
- Fetching data
- Managing state
- Handling logic
- Rendering UI
This leads to:
❌ Large components
❌ Poor readability
❌ Difficult testing
❌ Low reusability
To solve this, experienced React developers follow a classic and powerful design pattern:
Container vs Presentational Components
This lesson teaches you how to separate logic from UI, making your React code clean, scalable, and maintainable.
🎯 What You’ll Learn in This Lesson
By the end of this lesson, you will understand:
- What container components are
- What presentational components are
- Why separation of concerns matters
- How to structure components correctly
- Real-world examples
- When (and when not) to use this pattern
🧠 What Is Separation of Concerns?
Separation of concerns means:
Each part of your code should handle one responsibility only.
In React:
- Business logic ≠ UI rendering
- Data fetching ≠ styling
Mixing everything makes components hard to maintain.
🧩 Presentational Components (UI Components)
✅ What They Do
Presentational components:
- Focus only on UI
- Receive data via props
- Do NOT manage state (usually)
- Do NOT fetch data
They are also called:
- UI components
- Dumb components (older term)
🧠 Characteristics
✔ Stateless or minimal state
✔ Highly reusable
✔ Easy to test
✔ No business logic
🔍 Example — Presentational Component
function UserList({ users, onSelect }) {
return (
<ul>
{users.map(user => (
<li key={user.id} onClick={() => onSelect(user)}>
{user.name}
</li>
))}
</ul>
);
}
Notice:
- No API calls
- No state management
- Pure UI
🧩 Container Components (Logic Components)
✅ What They Do
Container components:
- Manage state
- Fetch data
- Handle business logic
- Pass data to presentational components
They are also called:
- Smart components
🧠 Characteristics
✔ Stateful
✔ Logic-heavy
✔ Less reusable
✔ Coordinates app behavior
🔍 Example — Container Component
function UserListContainer() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(data => setUsers(data));
}, []);
const handleSelect = user => {
console.log(user);
};
return <UserList users={users} onSelect={handleSelect} />;
}
This component:
- Fetches data
- Manages state
- Passes props to UI
🧠 How They Work Together
Container Component
↓
Presentational Component
The container:
- Knows how things work
The presentational component:
- Knows how things look
🆚 Before vs After (Why This Matters)
❌ Bad Practice (Everything Mixed)
function Users() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("/api/users").then(...);
}, []);
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Problems:
- Hard to reuse UI
- Hard to test logic
- Component grows quickly
✅ Good Practice (Separated)
<UserListContainer />
Internally:
- Logic is isolated
- UI is reusable
- Code is clean
🧠 Benefits of This Pattern
✅ Better readability
✅ Reusable UI components
✅ Easier testing
✅ Cleaner architecture
✅ Easier refactoring
This pattern scales extremely well.
🏗️ Folder Structure Example
components/
UserList.jsx // Presentational
containers/
UserListContainer.jsx
Clear responsibility boundaries.
🧠 Is This Pattern Still Relevant with Hooks?
Yes — absolutely.
Hooks:
- Simplify containers
- Do NOT eliminate separation of concerns
Hooks + this pattern = clean architecture.
🧠 Hooks + Container Pattern (Modern Approach)
Often combined with custom hooks:
function useUsers() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("/api/users").then(...);
}, []);
return users;
}
Then:
function UserListContainer() {
const users = useUsers();
return <UserList users={users} />;
}
✔ Clean
✔ Testable
✔ Reusable
❌ When NOT to Use This Pattern
Avoid it when:
- Component is very small
- Logic is minimal
- Over-abstraction adds complexity
Simple components don’t need extra layers.
🚨 Common Mistakes
❌ Putting logic in presentational components
Breaks separation.
❌ Making presentational components state-heavy
Reduces reusability.
❌ Over-engineering small features
Balance is key.
🎯 Best Practices (Senior-Level)
✅ Separate UI and logic clearly
✅ Keep presentational components simple
✅ Use containers for orchestration
✅ Combine with custom hooks
✅ Avoid unnecessary abstraction
❓ FAQs — Container vs Presentational
🔹 Is this pattern mandatory?
No — but highly recommended for large apps.
🔹 Is this pattern outdated?
No — it’s timeless and still relevant.
🔹 Can I use Redux or React Query inside containers?
Yes — containers are ideal for that.
🔹 Is this asked in interviews?
Yes — especially for architecture discussions.
🧠 Quick Recap
✔ Containers handle logic
✔ Presentational components handle UI
✔ Separation improves maintainability
✔ Hooks enhance this pattern
✔ Don’t overuse it
🎉 Conclusion
Clean React code is not about more code —
it’s about better separation.
Once you adopt the Container vs Presentational pattern:
- Your components become simpler
- Your UI becomes reusable
- Your app scales gracefully
This lesson lays the foundation for professional React architecture ⚛️🏗️
👉 Next Lesson
Lesson 22 — Higher-Order Components (HOC Pattern)