beginner18 min

Component Thinking: Breaking a UI into Pieces

Before any JSX or syntax, the actual skill React rewards: decomposing an interface into small, single-purpose, reusable pieces.

What you'll learn

  • Decompose a UI description into a hierarchy of named components
  • Apply single-responsibility thinking to decide where one component ends and another begins
  • Distinguish a reusable component from an accidental one-off copy of markup

Explanation

Before you write a line of JSX, React rewards a specific habit of mind: looking at a finished screen and seeing it as a tree of small, independently understandable pieces, rather than one large block of markup. A course catalog page is not "one big thing" — it's a page containing a search bar, containing a grid, containing cards, each card containing a title, a badge, and a progress bar. Each of those is a candidate component.

The practical test for "should this be its own component" is close to single-responsibility: does this piece have one clear job, and could it plausibly be reused or tested on its own? A "CourseCard" that renders one course's title, difficulty badge, and progress bar has one job. A giant "CoursesPage" component that also renders the individual title/badge/progress-bar markup inline, repeated for every course, has smuggled three jobs into one place — and the moment the badge's styling needs to change, you're hunting through a much larger file to find every copy.

A second, easily-missed distinction: a genuinely reusable component versus an accidental one-off. If "UserAvatar" and "CourseThumbnail" are really the same shape (an image, a fallback, a size prop) copy-pasted with different class names, that's an accidental duplicate hiding a real, reusable "Avatar" component. If they're superficially similar but actually serve different purposes with different future requirements, forcing them into one shared component too early creates awkward conditional logic that's worse than the duplication it replaced. Premature abstraction is a real cost, not a free win — the skill is recognizing genuine repetition, not eliminating every visual similarity.

This lesson's exercises are deliberately about the decomposition decision itself, in plain JavaScript, before any JSX syntax — component thinking is a design skill independent of any particular framework's syntax, and it's the skill that determines whether a codebase stays maintainable as it grows.

Example

Modeling a component tree as plain data (before any JSX) — a decomposition of a course-catalog page into named, single-purpose pieces.

const componentTree = {
  name: "CoursesPage",
  children: [
    { name: "SearchBar", children: [] },
    {
      name: "CourseGrid",
      children: [
        { name: "CourseCard", children: ["DifficultyBadge", "ProgressBar"] },
      ],
    },
  ],
};

function countComponents(node) {
  const childCount = node.children.reduce(
    (sum, child) => sum + (typeof child === "string" ? 1 : countComponents(child)),
    0,
  );
  return 1 + childCount;
}

console.log(countComponents(componentTree)); // 6

Try it yourself

Add a 'Pagination' sibling to CourseGrid inside CoursesPage's children, then re-run to see the count change.

Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.

Loading editor…

Guided exercise

Guided exercise

A component renders a user's name, avatar, AND independently fetches and renders that user's five most recent orders inline. Set hasSingleResponsibility to whether this obeys single-responsibility, and set suggestedSplit to an array of two suggested component names it should be split into.

Checks: correctly identifies the responsibility violation · suggests two component names

Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.

Loading editor…

Stuck? Get a hint.

Independent exercise

Independent exercise

Write a function hasAccidentalDuplicate(componentA, componentB) that returns true if two component descriptions (each an object with a `props` array) have identical prop lists (same props, any order) but different names — a sign they should probably be merged into one reusable component.

Checks: detects a real accidental duplicate · does not flag genuinely different components

Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.

Loading editor…

Stuck? Get a hint.

Common mistakes

  • Building one large component that does everything, deferring decomposition until it becomes painful to work in.
  • Merging two components that look visually similar today but serve genuinely different purposes, creating awkward conditional logic later.
  • Naming components after their visual position ("LeftBox") instead of their responsibility ("CourseFilterPanel"), making the codebase harder to navigate as it grows.

Knowledge check

Knowledge check

1. What is the practical test for whether a piece of UI should be its own component?
2. Why can merging two superficially similar components too early be a real cost?
3. Two components have identical prop lists but different names. What does this suggest?

Takeaway

Component thinking — deciding where one component's responsibility ends and another begins — is a design skill independent of JSX syntax, and it's what keeps a growing UI maintainable.

Summary

This lesson covered single-responsibility component decomposition and the difference between genuine reuse and premature abstraction, using plain JavaScript to model the decisions before any JSX syntax is introduced.

References

Your notes

Notes save automatically.

Finished this lesson?

Mark it complete to track your progress and schedule a future review.