Chapter 1 of 4

Thinking in Components

How to break a screen into components and where to draw the lines.

A component is a function that returns UI. That is the whole definition, but the interesting question is where one component should end and the next should begin.

A useful rule of thumb

Give a component one job. If you can describe what it does without using the word 'and', it is probably the right size.

  • ProductCard shows one product. Good.
  • ProductCardAndCheckoutForm shows a product and collects payment. Split it.
  • Avatar shows a user image. Good, and it will be reused everywhere.
Three small components compose into a list.
function Avatar({ user }) {
  return <img className="avatar" src={user.imageUrl} alt={user.name} />;
}

function UserRow({ user }) {
  return (
    <li className="user-row">
      <Avatar user={user} />
      <span>{user.name}</span>
    </li>
  );
}

function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <UserRow key={user.id} user={user} />
      ))}
    </ul>
  );
}

Components nest, they do not define

Compose components by rendering them inside each other. Never declare one component inside another component's body: React sees a brand new function type on every render, throws away the old DOM and remounts the subtree, losing its state.

// Wrong: Inner is redefined on every render of Outer
function Outer() {
  function Inner() {
    return <p>Hi</p>;
  }
  return <Inner />;
}

// Right: declare both at module level
function Inner() {
  return <p>Hi</p>;
}

function Outer() {
  return <Inner />;
}