Introduction: The Power of Reusable Components

Welcome back! In the last lesson, you learned how to build a simple React component using JSX. Now, let’s take the next step and see how you can make your components reusable. In real-world applications, you often need to display similar pieces of information in different places. Instead of copying and pasting code, React lets you create components that can be reused with different data. This makes your code cleaner, easier to manage, and less error-prone.

In this lesson, you will learn how to use something called props to pass information into your components. This is a key skill for building flexible and powerful React applications.

What Are Props?

Props (short for properties) are how we pass data from a parent component down to a child component.
Think of them as arguments to a function:

  • A function can behave differently depending on the arguments you pass.
  • A React component behaves differently depending on the props it receives.

Without props, every component would display the same static content. Props allow us to build flexible, reusable components.

The Problem Props Solve

Imagine you want to display multiple books. Without props, you’d have to copy the component code and hardcode each book’s title and author. That quickly becomes repetitive and hard to maintain.

Props solve this by letting you reuse the same component structure and simply supply different data each time. This makes your code cleaner, DRY (Don’t Repeat Yourself), and easier to scale.

Using Props In React

Think of props like ingredients you give to a recipe. The recipe (component) stays the same, but the final dish (output) can change depending on the ingredients (props) you use.

For example, let’s say you have a Greeting component:

function Greeting(props) {
  return <h1>Hello, {props.name}!</h1>;
}

Here, props.name is a value you can set when you use the component:

<Greeting name="Alice" />
<Greeting name="Bob" />

This will display:

Hello, Alice!
Hello, Bob!
  • The Greeting component is defined once.
  • Different data ("Alice", "Bob") is passed in as props.
  • The component renders differently each time without duplicating code.

props make your components flexible and reusable. Instead of hardcoding values, you can pass in different data each time you use the component.

Building And Using The BookCard Component

Let’s put this into practice by building a reusable BookCard component. This component will display the title and author of a book. Instead of making a new component for every book, you can use the same BookCard and just change the props.

Here’s how you can do it:

1. Create the BookCard Component

// src/features/catalog/BookCard.tsx
type Props = {
  title: string;
  author: string;
};

function BookCard({ title, author }: Props) {
  return (
    <article className="bg-slate-800 rounded-lg p-4 flex flex-col shadow-md hover:bg-slate-700 transition-colors" aria-label={`Book: ${title}`}>
      <h3 className="text-lg font-bold text-sky-400">{title}</h3>
      <p className="text-slate-400 mt-1">by {author}</p>
    </article>
  );
}

export default BookCard;

Explanation:

  • The BookCard component takes two props: title and author.
  • These props are used to display the book’s title and author inside the card.
  • The styling classes help make the card look nice, but the key idea is that the content comes from the props.

2. Use BookCard in Your App

Now, let’s use the BookCard component in your main app and pass different props to show different books:

// src/App.tsx

import BookCard from "./features/catalog/BookCard";

function App() {
  return (
    <main className="bg-slate-900 text-white min-h-screen p-8">
      <div className="max-w-4xl mx-auto">
        <h1 className="text-4xl font-bold text-sky-400">
          Welcome to ShelfPilot!
        </h1>
        <p className="mt-2 text-lg text-slate-300">
          Your personal reading tracker.
        </p>
        <div className="mt-8 grid grid-cols-1 md:grid-cols-3 gap-6">
          <BookCard title="Dune" author="Frank Herbert" />
          <BookCard title="The Hobbit" author="J.R.R. Tolkien" />
          <BookCard title="Project Hail Mary" author="Andy Weir" />
        </div>
      </div>
    </main>
  );
}

export default App;

Explanation:

  • Here, you use the BookCard component three times, each with different title and author props.
  • This shows how one component can be reused to display different data.
  • The result is a neat grid of book cards, each showing the correct title and author.

Output:

When you run this code, you will see three book cards on the page:

+---------------------+    +---------------------+    +---------------------+
| Dune                |    | The Hobbit          |    | Project Hail Mary   |
| by Frank Herbert    |    | by J.R.R. Tolkien   |    | by Andy Weir        |
+---------------------+    +---------------------+    +---------------------+

Each card is created from the same component, but the content is different because of the props you passed in.

How Props Enable Communication

Props let parents send information down to children. In our case:

  • App knows which books should be displayed.
  • BookCard knows how to display a single book, but not which one.
  • Props are the “bridge” of communication between the two. This separation makes our components modular:
  • The parent controls what data is shown.
  • The child controls how that data is displayed.
Testing Your Understanding
  • Positive Test: Add another <BookCard /> in App.tsx:
<BookCard title="Clean Code" author="Robert C. Martin" />

You should now see a fourth card.

  • Negative Test: Try removing the title prop:
<BookCard author="Unknown Author" />

TypeScript will show an error: Property 'title' is missing in type ... This happens because our Props type requires both title and author. Props enforce correct usage.

Extra Concept: Typescript Ternary Operator

So far, we’ve seen how props let us pass data into components. But what happens when some props are optional? In many cases, you’ll want to show one thing if a prop exists and another thing if it doesn’t. To do this cleanly, React developers often use two powerful tools in TypeScript/JavaScript: the ternary operator and the optional chaining operator.

1. The Ternary Operator (condition ? valueIfTrue : valueIfFalse)

The ternary operator is a shorthand way of writing an if/else expression inside JSX. It evaluates a condition and chooses between two values:

let age: number = 25;
let status: string = age >= 18 ? "Adult" : "Minor";

console.log(status); // Output: Adult
  • If the condition is true, the first value ("Adult") is used.
  • If false, the second value ("Minor") is used.

In a React component, this is very useful for conditional rendering. For example:

type Props = {
  name: string;
  role?: string;
};

function UserCard({ name, role }: Props) {
  return (
    <div>
      <h2>{name}</h2>
      {role ? (
        <p>User role: {role}</p>
      ) : (
        <p>The role of this user is not defined</p>
      )}
    </div>
  );
}
  • If role is provided, it renders: User role: admin.
  • If role is missing, it renders: The role of this user is not defined.

This allows your UI to adapt gracefully depending on the props.

Note: The ? in role?: string marks role as an optional property in the Props type. This means a UserCard can be created with or without a role value.

Don’t confuse this with the optional chaining operator (?.), which we’ll cover below. The optional chaining operator is used at runtime to safely access nested ? properties, while this ? is a TypeScript type annotation.

Extra Concept: Optional Chaining (?.)

The optional chaining operator (?.) is used when you’re not sure if a property exists. Instead of causing an error when accessing null or undefined, it will safely return undefined.

Example:

type User = {
  name: string;
  profile?: {
    bio?: string;
  };
};

const user1: User = { name: "Alice", profile: { bio: "Love reading" } };
const user2: User = { name: "Bob" }; // no profile

console.log(user1.profile?.bio); // Output: "Love reading"
console.log(user2.profile?.bio); // Output: undefined (no crash!)
  • Without optional chaining, user2.profile.bio would throw an error.
  • With ?., the expression simply evaluates to undefined when the chain breaks.

This is very useful when working with props that may or may not exist, especially if they are objects with deeper properties.

Extra Concept: Props + Conditional Logic = Flexible Components

By combining props, the ternary operator, and optional chaining, you can create components that handle both required and optional data gracefully.

For example, in a UserCard:

type Props = {
  id: number;
  name: string;
  username: string;
  role?: string;
};

function UserCard({ id, name, username, role }: Props) {
  return (
    <article className="bg-slate-800 rounded-lg p-4 flex flex-col shadow-md hover:bg-slate-700 transition-colors" aria-label={`User: ${name}`}>
      <h3 className="text-lg font-bold text-sky-400">{name}</h3>
      <p className="text-slate-400 mt-1">Username: {username}</p>
      <p className="text-slate-400 mt-1">ID: {id}</p>
      {/* Ternary operator for conditional UI */}
      {role ? (
        <p className="text-slate-300 mt-1">User role: {role}</p>
      ) : (
        <p className="text-slate-500 mt-1">The role of this user is not defined</p>
      )}
    </article>
  );
}

export default UserCard;

Key Takeaways

  • Ternary operator: a concise way to handle if/else inside JSX.
  • Optional chaining: safely access properties without crashing when something is undefined.
  • Used together with props, these tools make components more robust and flexible.

In your upcoming practice, you’ll use both of these operators when building the UserCard component. This will give you hands-on experience with conditional rendering and handling optional props.

Summary And What’s Next

In this lesson, you learned how to make your React components reusable by using props. You saw how props let you pass different data into a component, making it flexible and powerful. You also built a BookCard component and used it to display several books in your app.

  • Props let components receive input data.
  • They make components reusable and dynamic.
  • Props establish communication from parent → child.
  • In our project named ShelfPilot, we used props to display multiple books with a single BookCard component.

Next, you’ll get a chance to practice creating and using props yourself. This will help you get comfortable with one of the most important ideas in React. Keep going — your skills are growing with every lesson!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal