Skip to main content
ANVISoftware Solutions
Lesson 1 of 18Intermediate13 min

Thinking in Components

By the end of this lesson

Describe what a component is and split an interface into sensible ones.

A component is a function that takes data and returns a description of what should appear on screen.

That is the whole model. Everything else in React is a consequence of it. You do not write instructions to update the page; you describe what the page should look like for the current data, and React works out what to change.

A component is a function returning markup
TSX
interface CourseCardProps {
  title: string;
  level: string;
  duration: string;
}

export function CourseCard({ title, level, duration }: CourseCardProps) {
  return (
    <article className="rounded-2xl border p-6">
      <h3 className="font-semibold">{title}</h3>
      <p className="text-sm text-slate-600">
        {level} · {duration}
      </p>
    </article>
  );
}
  • The props interface states exactly what this component needs. Anything missing is a compile error rather than an empty space on the page.
  • Values are inserted with braces.
  • It returns markup and nothing else — no instructions about updating, no references to where it will appear.

Composition is the point

Small components assembled into a screen
TSX
export function CourseList({ courses }: { courses: Course[] }) {
  if (courses.length === 0) {
    return <p>No courses match those filters.</p>;
  }

  return (
    <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
      {courses.map((course) => (
        <CourseCard
          key={course.slug}
          title={course.title}
          level={course.level}
          duration={course.duration}
        />
      ))}
    </div>
  );
}
  • CourseList handles the collection and the layout. CourseCard handles one item. Neither knows about the other's concerns.
  • The empty case is handled first, which is a habit worth forming — an empty list is a normal state, not an edge case.
  • key lets React track which item is which across updates. Use a stable identifier, never the array index.

Where to draw component boundaries

Reasonable reasons to extract a component:

  • The same markup appears in more than one place
  • A section of a large component has a name you can state clearly
  • A piece of UI owns state that nothing else needs to know about
  • You want to test that piece on its own

Summary

  • A component is a function from data to a description of the UI
  • You describe the result rather than instructing the page how to change
  • Compose small components; extract for reuse, clarity, state ownership or testing
  • Keys must be stable identifiers, never array indexes

Practice

Attempt each one before opening the solution. Getting it wrong first is how the idea sticks.

Try it yourself

Try it yourself

Write a LessonRow component that shows a lesson title, its duration, and whether it is completed. Then write a LessonList that renders several of them and shows a message when there are none.

Show solution

The row handles one lesson and the list handles the collection and the empty case. Note that the completed state arrives as a prop — the row does not decide it, it displays it.

TSX
interface LessonRowProps {
  title: string;
  duration: string;
  isCompleted: boolean;
}

function LessonRow({ title, duration, isCompleted }: LessonRowProps) {
  return (
    <li className="flex items-center justify-between py-2">
      <span className={isCompleted ? "text-slate-500 line-through" : ""}>
        {title}
      </span>
      <span className="text-xs text-slate-500">{duration}</span>
    </li>
  );
}

export function LessonList({ lessons }: { lessons: LessonRowProps[] }) {
  if (lessons.length === 0) {
    return <p className="text-sm text-slate-500">No lessons in this module yet.</p>;
  }

  return (
    <ul className="divide-y">
      {lessons.map((lesson) => (
        <LessonRow key={lesson.title} {...lesson} />
      ))}
    </ul>
  );
}

Knowledge check

Nothing is recorded and there is no score. The explanation appears either way.

Why should you avoid using the array index as a React key?

Saved in this browser only.