No history yet

Component Design Patterns

Separating Brains from Beauty

When you first start building user interfaces, it's natural to mix logic and presentation in the same file. You fetch data, manage state, and define the HTML structure all in one place. This works for small projects, but as applications grow, it quickly becomes a tangled mess. Code becomes hard to read, difficult to test, and nearly impossible to reuse.

A more robust approach is to separate components based on their responsibilities. This leads us to a powerful pattern: separating 'smart' components from 'dumb' ones.

Smart components are concerned with how things work. They manage state, fetch data from APIs, and contain the business logic. They don't render much HTML themselves; instead, they pass data and functions down to other components.

Dumb components, often called [{}] are all about how things look. They receive data and callbacks exclusively through props. Their only job is to render the UI and call the functions they're given when a user interacts with them. They are completely unaware of the rest of the application. The same dumb component could be used in dozens of different contexts without any changes. This separation makes them highly reusable and easy to test visually in isolation. You can feed them some props and see exactly how they will render.

Lesson image

Think of a video player. A smart VideoPlayerContainer would be responsible for fetching the video URL, tracking the current playback time, and handling play/pause state. It would then pass this information down to a dumb VideoPlayerUI component. The UI component would simply display the video frame, a progress bar, and buttons, calling functions like onPlayClick or onSeek passed down via props. The UI component doesn't know where the video came from, only what to display.

// Smart/Container Component - Manages data and state
import React, { useState, useEffect } from 'react';
import UserList from './UserList';

const UserListContainer = () => {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

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

  if (loading) return <p>Loading...</p>;

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

// Dumb/Presentational Component - Renders UI from props
const UserList = ({ users }) => (
  <ul>
    {users.map(user => (
      <li key={user.id}>{user.name}</li>
    ))}
  </ul>
);