← Back

React.js + Next.js · Module 2. React Basics · Lesson 5

Component Properties (Props)

Props (short for properties) allow React components to receive data from other components.

Props make components flexible and reusable.

Without props, a component with fixed content always displays the same information.

With props, the same component can display different pizza names, sizes, prices, availability states, images, and other information.

Throughout this lesson, we will model the reusable pizza cards and controls needed for an online pizza-ordering website.

Props are one of the fundamental concepts of React.

You will learn

  1. What props are and why we use them.
  2. How data flows from parent to child components.
  3. How to pass props in JSX.
  4. How React receives props as an object.
  5. How to type props using TypeScript interfaces.
  6. How to pass multiple props.
  7. How to use strings, numbers, and booleans as props.
  8. How to create optional props.
  9. How to use props without destructuring.
  10. What props destructuring means.
  11. Why props are read-only.
  12. How to pass functions as props.
  13. Common mistakes when working with props.

REACT · 01

1. What Are Props?

Props are values passed from a parent component to a child component.

They work similarly to arguments passed to JavaScript functions.

JavaScript Function Example

function greet(name) {
  console.log("Hello " + name);
}

greet("Nikita");
greet("Alex");

The same function works with different arguments.

React components work in a similar way.

React Example

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

export default function App() {
  return (
    <div>
      <Greeting name="Nikita" />
      <Greeting name="Alex" />
    </div>
  );
}

Browser Result

Hello Nikita!

Hello Alex!

Two component instances receive different values through the same name prop.

Explanation

Greeting is a reusable component.

name="Nikita" passes a value to the component.

props.name reads the value.

The same component displays different information depending on the props it receives.


REACT · 02

2. Parent and Child Components

In React, components are organized into a component tree.

A parent component can pass information to its child components.

Example

function PizzaCard(props: { name: string }) {
  return <h2>{props.name}</h2>;
}

export default function App() {
  return (
    <div>
      <PizzaCard name="Margherita" />
    </div>
  );
}

Here:

  • App is the parent component.
  • PizzaCard is the child component.
  • name is the prop.
  • "Margherita" is the value passed through the prop.

Data Flow

App
 |
 | name="Margherita"
 |
 v
PizzaCard
 |
 | props.name
 |
 v
Margherita

Important: Props normally flow from parent components to child components.

This is called one-way data flow.


REACT · 03

3. React Passes Props as an Object

React automatically groups the attributes passed to a component into an object.

For example:

<PizzaCard name="Margherita" quantity={3} />

React provides a props object conceptually equivalent to:

{
  name: "Margherita",
  quantity: 3
}

Inside the component, we can access these values using dot notation:

props.name
props.quantity

Practical Example

interface PizzaCardProps {
  name: string;
  quantity: number;
}

function PizzaCard(props: PizzaCardProps) {
  return (
    <div>
      <h2>{props.name}</h2>
      <p>Quantity: {props.quantity}</p>
    </div>
  );
}

export default PizzaCard;

Explanation

props is the object received by the component.

props.name accesses the pizza name.

props.quantity accesses the number of pizzas.

This is ordinary JavaScript object property access.


REACT · 04

4. Typing Props with TypeScript Interfaces

In TypeScript, we should define the expected structure of component props.

We can use an interface or a type.

In this course, we will primarily use interface.

Example

interface PizzaCardProps {
  name: string;
}

This interface describes an object with one property:

name: string;

The property must contain a string.

Using the Interface

interface PizzaCardProps {
  name: string;
}

function PizzaCard(props: PizzaCardProps) {
  return (
    <h2>{props.name}</h2>
  );
}

export default PizzaCard;

Explanation

props: PizzaCardProps

means that the props parameter must follow the structure defined by PizzaCardProps.

TypeScript checks whether the correct values are provided.

Correct Usage

<PizzaCard name="Margherita" />

Incorrect Usage

<PizzaCard name={2048} />

This produces a TypeScript error because name must be a string, not a number.


REACT · 05

5. Passing Props in JSX

Props are passed using syntax similar to HTML attributes.

Example

<PizzaCard size="Small" />

The prop name is size.

The prop value is "Small".

Inside the component:

props.size

returns the string "Small".

Complete Example

interface PizzaCardProps {
  size: string;
}

function PizzaCard(props: PizzaCardProps) {
  return (
    <div>
      <h2>{props.size}</h2>
    </div>
  );
}

export default function App() {
  return (
    <div>
      <PizzaCard size="Small" />
      <PizzaCard size="Medium" />
      <PizzaCard size="Large" />
    </div>
  );
}

Browser Result

Small

Medium

Large

One component renders three sizes from three prop values.

One component displays three different sizes.


REACT · 06

6. Passing Multiple Props

A component can receive several props.

For example, a pizza card might need:

  • Pizza name.
  • Size.
  • Image URL.
  • Vegetarian status.

Define the Interface

interface PizzaCardProps {
  name: string;
  size: string;
  imageUrl: string;
}

Create the Component

interface PizzaCardProps {
  name: string;
  size: string;
  imageUrl: string;
}

function PizzaCard(props: PizzaCardProps) {
  return (
    <div>
      <h2>{props.name}</h2>

      <img
        src={props.imageUrl}
        alt={`Pizza ${props.name}`}
        width={320}
      />

      <p>Size: {props.size}</p>
    </div>
  );
}

export default PizzaCard;

Use the Component

import PizzaCard from "./PizzaCard";

export default function App() {
  return (
    <div>
      <PizzaCard
        name="Margherita"
        size="Small"
        imageUrl="/images/margherita-pizza.jpg"
      />

      <PizzaCard
        name="Pepperoni"
        size="Medium"
        imageUrl="/images/pepperoni-pizza.jpg"
      />
    </div>
  );
}

Explanation

The same PizzaCard component receives different data.

React renders each component using the values passed through props.

The image paths in this example assume that the files are stored inside Vite's public/images/ directory.

Browser Result

Margherita

Size: Small

Pepperoni

Size: Medium

The image areas are omitted here, but each card receives its own name, size, and image URL.

REACT · 07

7. Passing Different Data Types

Props can contain many kinds of JavaScript values.

Strings

<PizzaCard name="Margherita" />

String literals are normally written inside quotation marks.

Numbers

<PizzaCard quantity={3} />

Numbers are passed inside curly braces.

Booleans

<PizzaCard isVegetarian={true} />

Boolean values are also passed inside curly braces.

Variables

const quantity = 3;

<PizzaCard quantity={quantity} />

The variable is evaluated inside {}.

Expressions

<PizzaCard quantity={1 + 2} />

React receives the result of the expression.

Complete Example

interface PizzaCardProps {
  name: string;
  quantity: number;
  isVegetarian: boolean;
}

function PizzaCard(props: PizzaCardProps) {
  return (
    <div>
      <h2>{props.name}</h2>

      <p>Quantity: {props.quantity}</p>

      <p>
        {props.isVegetarian ? "Vegetarian" : "Contains meat"}
      </p>
    </div>
  );
}

export default PizzaCard;

Usage:

<PizzaCard
  name="Margherita"
  quantity={3}
  isVegetarian={true}
/>

Browser Result

Margherita

Quantity: 3

Vegetarian

String, number, and boolean props describe one pizza selection.

REACT · 08

8. Required and Optional Props

By default, properties declared in a TypeScript interface are required.

Required Props

interface PizzaCardProps {
  name: string;
  specialInstructions: string;
}

Both name and specialInstructions must be provided.

Optional Props

Add ? after the property name:

interface PizzaCardProps {
  name: string;
  specialInstructions?: string;
}

Now specialInstructions is optional.

Example

interface PizzaCardProps {
  name: string;
  specialInstructions?: string;
}

function PizzaCard(props: PizzaCardProps) {
  return (
    <div>
      <h2>{props.name}</h2>

      <p>
        Special instructions: {props.specialInstructions ?? "None"}
      </p>
    </div>
  );
}

export default PizzaCard;

Usage:

<PizzaCard name="Margherita" specialInstructions="Extra basil" />

<PizzaCard name="Pepperoni" />

Explanation

The ? means the prop can be omitted.

When omitted, props.specialInstructions is undefined.

The nullish coalescing operator ?? uses a fallback value when the left-hand value is null or undefined.

Browser Result

Margherita

Special instructions: Extra basil

Pepperoni

Special instructions: None

The fallback appears only when the optional prop is omitted.

REACT · 09

9. Props Without Destructuring

For beginners, accessing props directly through the props object can be easier to understand.

Example

interface PizzaCardProps {
  name: string;
  quantity: number;
}

function PizzaCard(props: PizzaCardProps) {
  return (
    <div>
      <h2>{props.name}</h2>
      <p>Quantity: {props.quantity}</p>
    </div>
  );
}

Here, every value clearly comes from the props object.

props.name
props.quantity

This is the approach used in most examples in these Dev Notes.


REACT · 10

10. Props Destructuring — Understanding the Alternative

Many React tutorials use destructuring.

Without Destructuring

function PizzaCard(props: PizzaCardProps) {
  return <h2>{props.name}</h2>;
}

With Destructuring

function PizzaCard({ name }: PizzaCardProps) {
  return <h2>{name}</h2>;
}

Both versions produce the same result.

What Is Destructuring?

Destructuring is a JavaScript feature that extracts properties from an object.

Example:

const pizza = {
  name: "Margherita",
  quantity: 3
};

const name = pizza.name;

This can also be written as:

const { name } = pizza;

In React, destructuring is optional.

For learning purposes, using props.name makes the data flow more explicit.


REACT · 11

11. Props Are Read-Only

Props should be treated as immutable values.

A child component must not directly modify the props it receives.

Incorrect Example

interface PizzaCardProps {
  quantity: number;
}

function PizzaCard(props: PizzaCardProps) {
  props.quantity = 5;

  return <p>{props.quantity}</p>;
}

This violates React's rules.

Correct Approach

interface PizzaCardProps {
  quantity: number;
}

function PizzaCard(props: PizzaCardProps) {
  return <p>Quantity: {props.quantity}</p>;
}

If a value needs to change, the component that owns the data should update it.

Later, we will learn how React state and callback props work together.

Important: React expects props to be treated as read-only, including objects and arrays passed through props.


REACT · 12

12. Passing Functions as Props

Props can also contain functions.

This allows a parent component to provide behavior to a child component.

Example — Reusable Button

Create Button.tsx:

interface ButtonProps {
  label: string;
  onPress: () => void;
}

function Button(props: ButtonProps) {
  return (
    <button onClick={props.onPress}>
      {props.label}
    </button>
  );
}

export default Button;

App.tsx

import Button from "./Button";

export default function App() {
  function handleAddToCart() {
    console.log("Pizza added to cart!");
  }

  return (
    <Button
      label="Add to cart"
      onPress={handleAddToCart}
    />
  );
}

Explanation

label contains the button text.

onPress contains a function.

props.onPress passes that function to the button's onClick.

When the user clicks the button, React executes the function provided by the parent.

Browser Result

The label and click handler are both provided by the parent component.

What Does () => void Mean?

onPress: () => void;

This is TypeScript syntax describing a function type.

It means that onPress must be a function that requires no arguments and returns no useful value.

The => in this case is part of a type declaration, not an arrow function implementation.


REACT · 13

13. Props vs State

Props and state are related but serve different purposes.

Quick rule: use props for information a component receives. Use state for information a component owns and needs to change over time.

Question Props State
Where does the value come from? A parent component The component that owns the value
Can this component change it directly? No — props are read-only Yes — through a state setter
How is it provided? Through JSX attributes With a hook such as useState
What causes a new value? The parent renders with new props User actions, API results, timers, or other events
Pizza-ordering example Pizza name or unit price Selected quantity or open/closed cart details

When to Use Props

Use props when:

  • a parent already knows the value;
  • several component instances need different input values;
  • a child needs a callback supplied by its parent;
  • the child should display or use the value without owning it.

Examples include a pizza name, size, price, button label, image URL, or onConfirm function.

When to Use State

Use state when:

  • the value changes while the user interacts with the component;
  • changing the value must update what React displays;
  • the component is responsible for remembering the current value.

Examples include a counter, selected tab, form input, modal visibility, loading status, or fetched data.

A Simple Decision Guide

Ask these questions in order:

  1. Does the value come from a parent? Use a prop.
  2. Does the component need to remember and change the value? Use state.
  3. Can the value be calculated from existing props or state? Calculate it during rendering; do not create additional state.
  4. Do several components need the same changing value? Keep the state in their closest shared parent and pass it down as props.

The same value can therefore be state in a parent and a prop in a child. These terms describe how each component uses the value, not the type of the value itself.

Practical Example

import { useState } from "react";

interface PizzaCardProps {
  name: string;
  unitPrice: number;
}

function PizzaCard(props: PizzaCardProps) {
  const state = useState(1);

  const quantity = state[0];
  const setQuantity = state[1];

  function addPizza() {
    setQuantity(quantity + 1);
  }

  return (
    <div>
      <h2>{props.name}</h2>

      <p>Price per pizza: {props.unitPrice} €</p>
      <p>Quantity: {quantity}</p>
      <p>Total: {props.unitPrice * quantity} €</p>

      <button onClick={addPizza}>
        Add pizza
      </button>
    </div>
  );
}

export default PizzaCard;

Explanation

name and unitPrice are received through props.

quantity is stored in local state.

total does not need separate state because it can be calculated from props.unitPrice and quantity during every render.

The component can update its own state, but it must not directly modify its props.

Common Mistake — Copying Props into State

Avoid copying a prop into state unless the component intentionally needs an independent editable value.

// Usually unnecessary: two places now store the same information.
const [name, setName] = useState(props.name);

If the component only displays the name, use props.name directly. Keeping one source of truth prevents the prop and state from becoming inconsistent.


REACT · 14

14. Practical Application — Pizza Cards in an Online Menu

Imagine an online menu where customers can compare pizzas and add their choices to an order.

Instead of creating separate components for Margherita, Pepperoni, and Vegetarian pizzas, we can create one reusable component.

PizzaCard.tsx

interface PizzaCardProps {
  id: number;
  name: string;
  size: string;
  quantity: number;
  isVegetarian: boolean;
}

function PizzaCard(props: PizzaCardProps) {
  return (
    <article>
      <h2>{props.name}</h2>

      <p>Size: {props.size}</p>
      <p>Quantity: {props.quantity}</p>

      <p>
        {props.isVegetarian ? "Vegetarian" : "Contains meat"}
      </p>
    </article>
  );
}

export default PizzaCard;

App.tsx

import PizzaCard from "./PizzaCard";

export default function App() {
  return (
    <main>
      <h1>Available Pizzas</h1>

      <PizzaCard
        id={1}
        name="Margherita"
        size="Small"
        quantity={3}
        isVegetarian={true}
      />

      <PizzaCard
        id={2}
        name="Pepperoni"
        size="Medium"
        quantity={1}
        isVegetarian={false}
      />
    </main>
  );
}

Advantages

One component can display many different pizzas.

Pizza data is separated from the component's markup.

Changing the structure of the pizza card requires editing only one component.

This is particularly useful for online menus, ordering systems, shopping carts, and restaurant applications.

Browser Result

Available Pizzas

Margherita

Small · Quantity: 3

Vegetarian

Pepperoni

Medium · Quantity: 1

Contains meat

Different prop values produce two cards while their structure remains identical.

REACT · 15

15. Common Beginner Mistakes

Mistake 1 — Forgetting to Pass a Required Prop

Incorrect:

<PizzaCard />

If name is required, TypeScript reports an error.

Correct:

<PizzaCard name="Margherita" />

Mistake 2 — Passing the Wrong Type

Incorrect:

<PizzaCard quantity="3" />

If quantity is defined as number, this is a string.

Correct:

<PizzaCard quantity={3} />

Mistake 3 — Forgetting Curly Braces Around Variables

Incorrect:

<PizzaCard quantity="plannedQuantity" />

This passes the literal text "plannedQuantity".

Correct:

<PizzaCard quantity={plannedQuantity} />

Mistake 4 — Using an Undefined Prop

Incorrect:

function PizzaCard(props: PizzaCardProps) {
  return <h2>{name}</h2>;
}

If name is not defined as a local variable, TypeScript reports an error.

Correct:

function PizzaCard(props: PizzaCardProps) {
  return <h2>{props.name}</h2>;
}

Mistake 5 — Modifying Props

Incorrect:

props.size = "Extra large";

Props are read-only. Ask the parent to provide a new value or use component state for data owned by the component.

Mistake 6 — Calling a Function Prop Immediately

Incorrect:

<button onClick={props.onPress()}>
  Confirm
</button>

Correct:

<button onClick={props.onPress}>
  Confirm
</button>

Pass the function itself so React can call it after the click.


REACT · 16

16. Practice Exercises

Exercise 1 — A Typed Greeting

Create a Greeting component with a required name: string prop. Render it twice with different names.

Exercise 2 — Pizza Details

Create a PizzaCard component with name, size, and quantity props. Access every value through the props object.

Exercise 3 — Optional Special Instructions

Add an optional specialInstructions prop and display None when it is missing.

Exercise 4 — Vegetarian Status

Add a boolean isVegetarian prop. Use a ternary expression to display the correct status.

Exercise 5 — Callback Prop

Create an ActionButton component that receives a label and an onPress function. Let App provide the click handler.


REACT · 17

17. Key Takeaways

  • Props pass data from parent components to child components.
  • React groups JSX attributes into a props object.
  • TypeScript interfaces describe the names and types of accepted props.
  • Strings use quotation marks, while numbers, booleans, variables, and expressions use curly braces.
  • A ? marks an optional TypeScript property.
  • Props are read-only and must not be modified by the receiving component.
  • Function props let a parent component provide behavior to a child.
  • Direct property access and destructuring are two ways to read props.
  • Props provide external data; state stores data owned and updated by a component.

REACT · 18

18. Further Reading

Next, learn how to inspect components, props, state, and renders with React Developer Tools.

← Back↑ Back to the top