React Container Component Pattern

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.

React Container Component Pattern

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.

Container Component Pattern React

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:

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.