Container and Presentational Components
One of the foundational patterns in React, this approach separates your components into two distinct categories: containers that manage state and logic, and presentational components that focus purely on rendering UI. This separation makes your code more modular, testable, and reusable. While modern React with hooks has made this pattern less rigid, understanding it is crucial for organizing complex applications and maintaining clean component boundaries.
Benefits
- ✓Clear separation of concerns
- ✓Easier to test presentational components
- ✓Better reusability
- ✓Simpler component structure
Use Cases
When you need to separate data fetching logic from UI rendering
Implementation
1// Container Component (Logic)2import React, { useState, useEffect } from 'react';3import UserList from './UserList';45const UserListContainer = () => {6 const [users, setUsers] = useState([]);7 const [loading, setLoading] = useState(true);8 const [error, setError] = useState(null);910 useEffect(() => {11 const fetchUsers = async () => {12 try {13 const response = await fetch('/api/users');14 const userData = await response.json();15 setUsers(userData);16 } catch (err) {17 setError(err.message);18 } finally {19 setLoading(false);20 }21 };2223 fetchUsers();24 }, []);2526 const handleUserDelete = (userId) => {27 setUsers(users.filter(user => user.id !== userId));28 };2930 return (31 <UserList32 users={users}33 loading={loading}34 error={error}35 onUserDelete={handleUserDelete}36 />37 );38};3940// Presentational Component (UI)41const UserList = ({ users, loading, error, onUserDelete }) => {42 if (loading) return <div className="spinner">Loading...</div>;43 if (error) return <div className="error">Error: {error}</div>;44 if (users.length === 0) return <div>No users found</div>;4546 return (47 <div className="user-list">48 <h2>Users</h2>49 {users.map(user => (50 <div key={user.id} className="user-card">51 <h3>{user.name}</h3>52 <p>{user.email}</p>53 <button onClick={() => onUserDelete(user.id)}>54 Delete55 </button>56 </div>57 ))}58 </div>59 );60};