🎁 React Props: Passing Gifts Between Components
The Gift Box Analogy
Imagine you have a gift box. You can put anything inside—a toy, a note, or even another smaller box. When you give this box to a friend, they can open it and use what’s inside.
In React, Props work exactly like gift boxes!
- The parent component is like you (the gift giver)
- The child component is like your friend (the receiver)
- Props are the items inside the gift box
🎯 Props Fundamentals
What Are Props?
Props (short for “properties”) are how we send data from one component to another.
// Parent gives a gift
<WelcomeCard name="Alex" age={10} />
// Child receives the gift
function WelcomeCard(props) {
return (
<div>
<h1>Hello, {props.name}!</h1>
<p>You are {props.age} years old</p>
</div>
);
}
Key Rules About Props
- Props flow DOWN — Parent → Child only
- Props are READ-ONLY — You cannot change them inside the child
- Props can be ANYTHING — Strings, numbers, objects, functions, even other components!
graph TD A[Parent Component] -->|sends props| B[Child Component] B -->|uses props| C[Renders UI]
Why Can’t We Change Props?
Think about it: If your friend opens your gift box and changes what’s inside, you’d be confused! The gift was yours to give, not theirs to modify.
Same in React. The parent owns the data, the child just reads and uses it.
✂️ Destructuring Props
The Messy Way vs The Clean Way
Writing props.name, props.age, props.color everywhere gets tiring!
Destructuring is like opening the gift box and laying out each item separately.
// ❌ Messy: Saying "props" every time
function Card(props) {
return <h1>{props.name} is {props.age}</h1>;
}
// ✅ Clean: Destructuring in function parameter
function Card({ name, age }) {
return <h1>{name} is {age}</h1>;
}
You Can Destructure Anywhere
// Option 1: In the function parameter
function Profile({ name, avatar, bio }) {
return (
<div>
<img src={avatar} alt={name} />
<h2>{name}</h2>
<p>{bio}</p>
</div>
);
}
// Option 2: Inside the function body
function Profile(props) {
const { name, avatar, bio } = props;
// ... same result
}
Real Example
// Parent
<UserBadge
username="cosmic_coder"
level={42}
isOnline={true}
/>
// Child with destructuring
function UserBadge({ username, level, isOnline }) {
return (
<div>
<span>{username}</span>
<span>Level: {level}</span>
{isOnline && <span>🟢 Online</span>}
</div>
);
}
🎁 Default Props
What If Someone Forgets to Send a Gift?
Sometimes a parent doesn’t pass a prop. Instead of your component breaking, you can set a backup value (default).
// If no color is passed, use "blue"
function Button({ label, color = "blue" }) {
return (
<button style={{ backgroundColor: color }}>
{label}
</button>
);
}
// Usage
<Button label="Click Me" /> // color = "blue"
<Button label="Stop" color="red" /> // color = "red"
Multiple Defaults
function Avatar({
src = "/default-avatar.png",
size = 50,
alt = "User"
}) {
return (
<img
src={src}
width={size}
height={size}
alt={alt}
/>
);
}
// All these work!
<Avatar />
<Avatar src="/me.jpg" />
<Avatar size={100} alt="Profile" />
graph TD A[Prop Passed?] -->|Yes| B[Use Passed Value] A -->|No| C[Use Default Value] B --> D[Render Component] C --> D
👶 The Children Prop
A Special Kind of Gift
Sometimes you want to wrap content between your component tags. React automatically puts this content in a special prop called children.
// Parent wraps content
<Card>
<h1>Welcome!</h1>
<p>This is inside the card</p>
</Card>
// Child receives it via children
function Card({ children }) {
return (
<div className="card-box">
{children}
</div>
);
}
Think of It Like an Envelope
The children prop is like an envelope:
- You can put anything inside
- The child component decides where to display it
// A reusable container
function FancyBorder({ children, color }) {
return (
<div style={{ border: `3px solid ${color}` }}>
{children}
</div>
);
}
// Use it anywhere!
<FancyBorder color="purple">
<h2>Any content works here!</h2>
<button>Even buttons</button>
</FancyBorder>
Real-World Use: Modal Window
function Modal({ isOpen, children }) {
if (!isOpen) return null;
return (
<div className="modal-backdrop">
<div className="modal-content">
{children}
</div>
</div>
);
}
// Usage
<Modal isOpen={true}>
<h1>Are you sure?</h1>
<button>Yes</button>
<button>No</button>
</Modal>
🌊 Spreading Props
When You Have Many Gifts to Pass
Imagine you have a bag full of 10 gifts. Instead of handing each one separately, you dump the whole bag at once!
The spread operator (...) does exactly this.
// Without spread: tedious!
<UserCard
name={user.name}
age={user.age}
email={user.email}
avatar={user.avatar}
/>
// With spread: elegant!
<UserCard {...user} />
How It Works
const person = {
name: "Luna",
age: 8,
hobby: "painting"
};
// These are the same:
<Profile {...person} />
<Profile name="Luna" age={8} hobby="painting" />
Combining Spread with Individual Props
const settings = { theme: "dark", size: "large" };
// Spread first, then override
<Button {...settings} size="small" />
// Result: theme="dark", size="small"
// Override first, then spread (spread wins)
<Button size="small" {...settings} />
// Result: theme="dark", size="large"
graph LR A[Object with Props] -->|spread ...| B[Individual Props] B --> C[Component Receives All]
⚠️ Use Spread Wisely
Spreading is convenient but can make code harder to understand. If someone reads <Card {...data} />, they can’t immediately see what props are being passed.
Best practice: Use spread for well-known objects, but be explicit when clarity matters.
⚔️ State vs Props
The Big Difference
| Feature | Props | State |
|---|---|---|
| Who owns it? | Parent | Component itself |
| Can it change? | No (read-only) | Yes (use setState) |
| Where does it come from? | Passed in | Created inside |
| Used for? | Configuration | Dynamic data |
Analogy Time!
- Props = Gifts you receive (you can’t change what someone gave you)
- State = Your own toys (you can play, move, or break them)
function Counter({ startValue }) { // prop
const [count, setCount] = useState(startValue); // state
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Add One
</button>
</div>
);
}
// Usage
<Counter startValue={10} />
When to Use Which?
graph TD A[Need to pass data from parent?] -->|Yes| B[Use Props] A -->|No| C[Does data change over time?] C -->|Yes| D[Use State] C -->|No| E[Use a constant]
Props Can Trigger State Changes
function Greeting({ initialName }) {
// Prop sets the INITIAL state
const [name, setName] = useState(initialName);
return (
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
);
}
Key insight: Props configure the component. State manages what happens AFTER the component is configured.
🎯 Quick Summary
| Concept | One-Liner |
|---|---|
| Props | Data passed from parent to child |
| Destructuring | Unpack props for cleaner code |
| Default Props | Backup values when props are missing |
| Children | Content placed between component tags |
| Spreading | Pass all object properties as props at once |
| State vs Props | Props are gifts; State is your own stuff |
🚀 You’re Ready!
You now understand how React components talk to each other through props. Like a well-organized gift exchange, props keep your data flowing smoothly from parents to children.
Remember:
- Props go DOWN (parent → child)
- Props are READ-ONLY
- Use destructuring for clean code
- Set defaults for safety
childrenis for wrapping content- Spread when passing many props
- State is for data the component controls itself
Go build something amazing! 🎉