React

React Props — Passing Data & Building Reusable Components

Thirdy Gayares
16 min read

🎓 What You Will Learn

  • Props Basics: Pass data from parent to child components
  • Destructuring: Clean syntax for accessing props
  • Default Values: Set fallback prop values
  • Children Prop: Build flexible wrapper components
  • Prop Types: TypeScript for type-safe components
  • Prop Drilling: Recognize and avoid common pitfalls
  • Reusable Components: Build flexible, composable UIs
  • Best Practices: Pro patterns and conventions
1

What Are Props?

Props (short for "properties") are how components communicate in React. They let you pass data from a parent component to a child component, similar to function parameters.

Props enable component reusability. Instead of creating a different component for every variation, you create ONE component and customize it with different props.

Key concept: Props are read-only and flow only downward (parent → child). They cannot be modified by the child component.
2

Basic Props — Passing Data

Props are passed as attributes on components, just like HTML attributes.

props-basics.jsx
// Child component receives props
function Greeting({ name, emoji }) {
  return <p>{emoji} Hello, {name}!</p>;
}

// Parent component passes props as attributes
export function App() {
  return (
    <>
      <Greeting name="Alice" emoji="👋" />
      <Greeting name="Bob" emoji="😊" />
      <Greeting name="Charlie" emoji="🎉" />
    </>
  );
}

👩‍💻

Alice

Frontend Developer

🧑‍💼

Bob

Project Manager

🎨

Diana

UI Designer

3

Destructuring — Clean Syntax

Destructuring extracts props into separate variables, making code cleaner and more readable.

destructuring.jsx
// Without destructuring (verbose)
function User(props) {
  return <p>{props.name} - {props.email}</p>;
}

// With destructuring (clean!)
function User({ name, email }) {
  return <p>{name} - {email}</p>;
}

// Also works with default values
function Button({ text = "Click", color = "blue" }) {
  return <button className={color}>{text}</button>;
}

👩‍💼

Alice Chen

[email protected]

✓ Verified

👨‍💻

Bob Smith

[email protected]

4

Default Props — Fallback Values

Use = syntax to provide default values when props aren't passed.

default-values.jsx
function Button({ text = "Click me!", variant = "primary" }) {
  return (
    <button className={variant}>{text}</button>
  );
}

// Using defaults (all three work!)
<Button />
<Button text="Submit" />
<Button text="Delete" variant="danger" />

Default Props

Custom Props

5

The Children Prop — Building Wrappers

The children prop is special — it contains whatever is passed between component tags. This enables flexible, reusable wrapper components.

children-prop.jsx
// Component definition
function Card({ title, children }) {
  return (
    <div className="card">
      <h2>{title}</h2>
      {children}  {/* This is what goes inside! */}
    </div>
  );
}

// Usage: Content goes between tags
<Card title="Welcome">
  <p>This is a paragraph</p>
  <button>Click me</button>
</Card>

<Card title="Features">
  <ul>
    <li>Feature 1</li>
    <li>Feature 2</li>
  </ul>
</Card>

Welcome

👋 This content is passed as children to the Card component.

Features

  • Reusable wrapper
  • Flexible content
  • Clean code

Code Snippet

const x = 42;
6

Prop Drilling & Solutions

Prop drilling happens when you pass props through many levels of components even though intermediate components don't use them. This makes code hard to maintain.

❌ Prop Drilling Problem: Passing theme prop from App → Page → Layout → Card → Text

✅ Solutions:

  • useContext — Share global data without passing through every component
  • useReducer — Centralize complex state
  • • State Management Libraries — Redux, Zustand, Jotai

❌ Prop Drilling Problem

Props passed through many levels:

App → Page → Layout → Card → Text

✅ Solution: useContext

Access data directly where needed:

App → [useContext] → Text

7

Type-Safe Props with TypeScript

Use TypeScript to define prop types and catch errors at compile time instead of runtime.

typescript-props.tsx
// Define prop interface
interface ButtonProps {
  text: string;
  color?: "blue" | "red" | "green";  // Union type
  onClick: (e: React.MouseEvent) => void;
  disabled?: boolean;
}

// Component uses the interface
function Button({ text, color = "blue", onClick, disabled }: ButtonProps) {
  return (
    <button
      onClick={onClick}
      className={color}
      disabled={disabled}
    >
      {text}
    </button>
  );
}

// TypeScript validates these
<Button
  text="Submit"
  color="green"
  onClick={() => console.log("clicked")}
/>

// This would error:
// <Button text="Submit" color="purple" />  // ❌ not in union

Laptop

$999

4.8/5

✓ In Stock

Phone

$599

4.5/5

✓ In Stock

Tablet

$399

4.2/5

Out of Stock

Monitor

$299

5/5

✓ In Stock

8

Best Practices

Use descriptive names: userName not n
Keep components small: Easier to understand prop flow
Use TypeScript: Catch prop errors before runtime
Destructure in function signature: Cleaner than props.x
Document complex props: Use JSDoc comments
Avoid prop drilling: Use Context API for deeply nested data
9

Props vs State

AspectPropsState
SourceParent componentComponent itself
MutabilityRead-onlyCan change
PurposeConfigure componentTrack data changes
RerenderYes (when props change)Yes (when state changes)
Example<Button color='blue' />const [count, setCount] = useState(0)
10

Common Mistakes

1Mistake: Trying to Modify Props
mistake-mutate.jsx
// ❌ BAD: Props are read-only!
function User({ name }) {
  name = "Bob";  // Don't do this!
  return <p>{name}</p>;
}

// ✅ GOOD: Use state if you need to change
function User({ initialName }) {
  const [name, setName] = useState(initialName);
  return (
    <>
      <p>{name}</p>
      <input onChange={(e) => setName(e.target.value)} />
    </>
  );
}
2Mistake: Too Many Props
mistake-many-props.jsx
// ❌ BAD: Too many props is hard to use
function User({ name, email, phone, address, city, zip, country }) {
  // Confusing!
}

// ✅ GOOD: Group related props into object
function User({ name, contact, address }) {
  // Cleaner!
}

<User
  name="Alice"
  contact={{ email: "...", phone: "..." }}
  address={{ city: "...", zip: "..." }}
/>
3Mistake: Prop Drilling Too Deep
❌ Bad: Passing props through 5+ levels of components
✅ Good: Use useContext or state management for deeply nested data
11

Real-World Example: Product Card

ProductCard.tsx
interface ProductCardProps {
  id: number;
  name: string;
  price: number;
  image: string;
  inStock: boolean;
  onAddToCart: (id: number) => void;
}

function ProductCard({
  id,
  name,
  price,
  image,
  inStock,
  onAddToCart,
}: ProductCardProps) {
  return (
    <div className="card">
      <img src={image} alt={name} />
      <h3>{name}</h3>
      <p className="price">${price}</p>
      <p className="stock">
        {inStock ? "✓ In Stock" : "Out of Stock"}
      </p>
      <button
        onClick={() => onAddToCart(id)}
        disabled={!inStock}
      >
        Add to Cart
      </button>
    </div>
  );
}

// Usage
<ProductCard
  id={1}
  name="Laptop"
  price={999}
  image="/laptop.jpg"
  inStock={true}
  onAddToCart={handleAddToCart}
/>
12

Advanced Patterns

1Spread Operator for Props
spread-props.jsx
// Spread all props to child component
function Button(props) {
  return <button {...props}>Click</button>;
}

// This passes through all attributes
<Button className="large" disabled={false} data-test="btn" />
2Render Props Pattern
render-props.jsx
// Function as prop
function ListRenderer({ data, render }) {
  return (
    <ul>
      {data.map((item) => (
        <li key={item.id}>{render(item)}</li>
      ))}
    </ul>
  );
}

// Usage
<ListRenderer
  data={users}
  render={(user) => <span>{user.name}</span>}
/>
13

What's Next?

🚀 Next Learning Topics:
  • React Hooks: useState for component state
  • useContext: Avoid prop drilling with global state
  • Component Composition: Build complex UIs from simple components
  • TypeScript: Full type safety for props and state
  • Testing: Test components with different props

Master props through practice! 💪 Build reusable components by experimenting with different prop combinations. Props are the foundation of component-driven development!

About the Author

TG

Thirdy Gayares

Passionate developer creating custom solutions for everyone. I specialize in building user-friendly tools that solve real-world problems while maintaining the highest standards of security and privacy.