Last updated: Apr 29, 2026

Container / Presentational

The Container / Presentational pattern splits a component into two: one that handles data and state, and one that handles how things look. This gives a clear separation of concerns between logic and UI.

How It Works

  • Container component — fetches data, manages state, and passes everything down as props.
  • Presentational component — receives props and renders UI. No awareness of where the data comes from.

Example

// Container
function UserListContainer() {
  const [users, setUsers] = useState<User[]>([]);

  useEffect(() => {
    fetch("/api/users")
      .then((res) => res.json())
      .then(setUsers);
  }, []);

  return <UserList users={users} />;
}

// Presentational
function UserList({ users }: { users: User[] }) {
  return (
    <ul>
      {users.map((u) => (
        <li key={u.id}>{u.name}</li>
      ))}
    </ul>
  );
}

The container owns the fetch logic; the presentational component is a pure function of its props and easy to reuse or test in isolation.

Trade-offs

ProsCons
Clear separation of data and UIExtra layer of components
Presentationals are easy to reuse and testCan feel like boilerplate for simple cases
Containers are swappable (e.g. different data source, same UI)Prop drilling if nesting gets deep

Note on Hooks

With custom hooks, much of what containers used to do (fetching, state, side effects) can live in a hook instead. A useUsers hook replaces the container, and the component handles both the hook call and the render. This reduces the need for the pattern in modern React, though the mental model of separating data from presentation is still valuable.