I have been building React applications. One thing I learned early on is that messy components are a nightmare to maintain.
When you mix data fetching logic with UI rendering, your code becomes hard to read. It also becomes nearly impossible to test or reuse.
That is where the Container Component pattern comes in. It is one of the most effective ways to keep your codebase clean and professional.
In this tutorial, I will show you exactly how to implement this pattern using real-world examples.
What is the Container Component Pattern?
The Container Component pattern is a design strategy that separates “how things work” from “how things look.”
In this pattern, we split a single component into two distinct parts: the Container and the Presentational component.
The Container handles the “logic.” This includes fetching data from an API, managing state, or handling events.
The Presentational component handles the “view.” It simply receives data via props and displays it to the user.
Why Should You Use This Pattern?
I started using this pattern because it made my components reusable. I could change the data source without touching the UI code.
It also makes your code much easier to test. You can test the logic in the container and the styling in the presentational component separately.
If you are working in a large team in the USA, this separation allows designers to work on UI components while developers handle the data layer.
Method 1: Use Class-Based Container Components
While many developers have moved to Hooks, you will still encounter class components in many enterprise projects in the US.
In this example, I will build a “California Tech Job Board” component. The container will fetch the jobs, and the UI component will display them.
The Presentational Component (UI)
This component doesn’t care where the data comes from. It just renders a list of jobs.
import React from 'react';
// This is the Presentational Component
// It only focuses on how the job list looks
const JobList = ({ jobs, loading, error }) => {
if (loading) return <p>Loading Silicon Valley job openings...</p>;
if (error) return <p>Error loading jobs: {error}</p>;
return (
<div style={{ padding: '20px', fontFamily: 'Arial' }}>
<h1>Tech Jobs in California</h1>
<ul style={{ listStyleType: 'none' }}>
{jobs.map((job) => (
<li key={job.id} style={{ borderBottom: '1px solid #ccc', padding: '10px 0' }}>
<strong>{job.title}</strong> - {job.company}
<br />
<small style={{ color: '#666' }}>Location: {job.location}</small>
</li>
))}
</ul>
</div>
);
};
export default JobList;The Container Component (Logic)
This component handles the API call and manages the state.
import React, { Component } from 'react';
import JobList from './JobList';
// This is the Container Component
// It handles fetching the data
class JobBoardContainer extends Component {
constructor(props) {
super(props);
this.state = {
jobs: [],
loading: true,
error: null,
};
}
componentDidMount() {
// Simulating an API call to a US Job Portal
setTimeout(() => {
const mockData = [
{ id: 1, title: 'Senior React Developer', company: 'Google', location: 'Mountain View, CA' },
{ id: 2, title: 'Frontend Engineer', company: 'Netflix', location: 'Los Gatos, CA' },
{ id: 3, title: 'Software Architect', company: 'Apple', location: 'Cupertino, CA' },
];
if (mockData) {
this.setState({ jobs: mockData, loading: false });
} else {
this.setState({ error: 'Failed to fetch data', loading: false });
}
}, 1500);
}
render() {
// Passing the state to the presentational component via props
return (
<JobList
jobs={this.state.jobs}
loading={this.state.loading}
error={this.state.error}
/>
);
}
}
export default JobBoardContainer;You can see the output in the screenshot below.

Method 2: Use Functional Components with Hooks
This is my favorite way to write containers today. It is much cleaner and uses modern React features like useState and useEffect.
Let’s build a “New York Real Estate Listing” feature using this approach.
The Presentational Component
import React from 'react';
// UI Component for NYC Listings
const PropertyView = ({ properties, isLoading }) => {
if (isLoading) {
return <h2 style={{ textAlign: 'center' }}>Searching Manhattan listings...</h2>;
}
return (
<div style={{ maxWidth: '800px', margin: 'auto' }}>
<h1 style={{ color: '#2c3e50' }}>Featured NYC Properties</h1>
<div style={{ display: 'grid', gap: '20px' }}>
{properties.map(item => (
<div key={item.id} style={{ boxShadow: '0 4px 8px rgba(0,0,0,0.1)', padding: '15px' }}>
<h3>{item.address}</h3>
<p>Price: <strong>{item.price}</strong></p>
<span style={{ background: '#e74c3c', color: 'white', padding: '5px' }}>
{item.neighborhood}
</span>
</div>
))}
</div>
</div>
);
};
export default PropertyView;The Container Component
import React, { useState, useEffect } from 'react';
import PropertyView from './PropertyView';
// Logic Component
const PropertyContainer = () => {
const [properties, setProperties] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Simulating data fetching from a US real estate database
const fetchProperties = async () => {
try {
await new Promise(resolve => setTimeout(resolve, 2000));
const data = [
{ id: 101, address: 'Upper West Side Condo', price: '$2,500,000', neighborhood: 'Manhattan' },
{ id: 102, address: 'Brooklyn Heights Brownstone', price: '$4,200,000', neighborhood: 'Brooklyn' },
{ id: 103, address: 'Astoria Modern Loft', price: '$950,000', neighborhood: 'Queens' }
];
setProperties(data);
setIsLoading(false);
} catch (error) {
console.error("Listing error:", error);
}
};
fetchProperties();
}, []);
return <PropertyView properties={properties} isLoading={isLoading} />;
};
export default PropertyContainer;You can see the output in the screenshot below.

I don’t use this for every single component. If a component is very small and doesn’t have much logic, it’s okay to keep it together.
However, if you are building a complex dashboard or a data-heavy application, this pattern is a lifesaver.
It is particularly useful when you need to use the same UI with different data sources (e.g., one for production and one for testing).
Key Differences Between Container and Presentational Components
To make it easier for you to remember, I have listed the main differences I keep in mind during development:
- Container Components: Concerned with data, API calls, and logic. They usually have state and don’t contain much CSS.
- Presentational Components: Concerned with how the app looks. They rarely have state (unless it’s UI state like a toggle) and rely on props.
Test the Pattern
One of the biggest wins I’ve found with this pattern is how easy it makes testing.
You can use a tool like Jest to test your Container’s logic without worrying about the HTML structure.
Similarly, you can use Storybook to view your Presentational components in different states (loading, error, or with data) without needing an actual API.
In this guide, I showed you how the Container Component pattern can clean up your React code.
I have used this pattern in many professional projects across various US-based tech companies. It consistently makes the code more manageable.
You may also read:
- React Async Functional Component
- How to Fix Framer Motion Drag Not Working in React
- React Inline Style Component
- React Render Component from Variable

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.