React Components vs Containers

When I first started working with React over a decade ago, the distinction between components and containers was not always clear. Over the years, I realized that separating these two concepts properly can make your React applications much easier to maintain and scale.

In this article, I’ll share my firsthand experience on what React components and containers really mean, why the distinction matters, and how to implement them effectively.

Whether you’re building a dashboard for a US-based financial service or a customer portal for an e-commerce site, understanding this separation will help you write cleaner, more reusable code.

What Are React Components and Containers?

In React, components are the building blocks of your UI. They are responsible for how things look, the markup, styles, and UI logic.

On the other hand, containers (sometimes called smart components) are responsible for how things work, managing state, fetching data, and passing props down to components.

Think of components as the “dumb” or presentational parts that just display data, while containers are the “smart” parts that handle the business logic.

Separate Components and Containers

From my experience, mixing UI and logic in the same component can quickly lead to messy code. When components do too many things, they become harder to test, reuse, and maintain.

By separating components and containers, you get:

  • Better reusability: Presentational components can be reused across different parts of your app or even different projects.
  • Easier testing: You can test your UI components independently of the business logic.
  • Clearer responsibilities: Containers handle data and state, components handle rendering.

Method 1: Use Functional Components as Presentational Components

In modern React, functional components are the go-to for creating simple UI pieces. Here’s an example of a presentational component that displays a user profile card:

// UserProfile.js - Presentational Component
import React from 'react';

const UserProfile = ({ name, email, avatarUrl }) => {
  return (
    <div style={styles.card}>
      <img src={avatarUrl} alt={`${name}'s avatar`} style={styles.avatar} />
      <h2>{name}</h2>
      <p>{email}</p>
    </div>
  );
};

const styles = {
  card: {
    border: '1px solid #ddd',
    padding: 20,
    borderRadius: 8,
    maxWidth: 300,
    margin: 'auto',
    textAlign: 'center',
  },
  avatar: {
    width: 100,
    borderRadius: '50%',
  },
};

export default UserProfile;

I executed the above example code and added the screenshot below.

React Components vs Containers

This component simply receives data via props and renders it. It has no idea where the data comes from or how it’s managed.

Method 2: Create Containers to Manage Data and State

Containers handle fetching data, managing state, and passing data down to presentational components. Here’s a container that fetches user data from a mock API and passes it to UserProfile:

// UserProfileContainer.js - Container Component
import React, { useState, useEffect } from 'react';
import UserProfile from './UserProfile';

const UserProfileContainer = () => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Simulate API call to fetch user data (e.g., from a US-based user database)
    fetch('https://jsonplaceholder.typicode.com/users/1')
      .then((response) => {
        if (!response.ok) throw new Error('Network response was not ok');
        return response.json();
      })
      .then((data) => {
        setUser({
          name: data.name,
          email: data.email,
          avatarUrl: `https://i.pravatar.cc/150?u=${data.email}`, // Random avatar
        });
        setLoading(false);
      })
      .catch((err) => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <p>Loading user profile...</p>;
  if (error) return <p>Error loading user profile: {error}</p>;

  return <UserProfile {...user} />;
};

export default UserProfileContainer;

I executed the above example code and added the screenshot below.

React Components and Containers

Notice how the container handles:

  • Data fetching
  • Loading and error states
  • Passing sanitized data to the presentational component

This keeps the UI component clean and focused only on rendering.

Method 3: Use Redux or Context for State Management in Containers

For larger US-based applications, such as an enterprise payroll system or a healthcare portal, you often need centralized state management. Containers can connect to Redux or React Context to manage global state.

Here’s a quick example with React Context:

// UserContext.js
import React, { createContext, useState, useEffect } from 'react';

export const UserContext = createContext();

export const UserProvider = ({ children }) => {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // Fetch user data once when app loads
    fetch('https://jsonplaceholder.typicode.com/users/1')
      .then((res) => res.json())
      .then((data) => setUser(data));
  }, []);

  return <UserContext.Provider value={user}>{children}</UserContext.Provider>;
};
// UserProfileContainer.js
import React, { useContext } from 'react';
import { UserContext } from './UserContext';
import UserProfile from './UserProfile';

const UserProfileContainer = () => {
  const user = useContext(UserContext);

  if (!user) return <p>Loading...</p>;

  return (
    <UserProfile
      name={user.name}
      email={user.email}
      avatarUrl={`https://i.pravatar.cc/150?u=${user.email}`}
    />
  );
};

export default UserProfileContainer;

Using context or Redux keeps your containers focused on state management, while your components stay purely presentational.

Best Practices from My Experience

  • Keep presentational components stateless whenever possible.
  • Use containers for side effects like API calls and complex logic.
  • Name your files clearly: UserProfile.js for the component, UserProfileContainer.js for the container.
  • Avoid mixing concerns to make your codebase easier to maintain.
  • Leverage hooks like useEffect and useContext inside containers for cleaner code.

Mastering the distinction between React components and containers has helped me write cleaner, more scalable applications, especially when working on complex projects like US healthcare portals and financial dashboards. This approach improves collaboration across teams and makes onboarding new developers much easier.

If you’re starting with React or looking to improve your code organization, try separating your components and containers as I’ve shown here. It’s a simple change that pays off big in the long run.

You may 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.