Passing Multiple Props to React Components: From Basic to Elegant Patterns
Passing Multiple Props to Child Components
When building React applications, you often need to pass several properties to a child component—for example, a card component that displays a news article might need the headline, author, publication date, and body text. Writing these out individually can become tedious. React provides elegant syntax to hendle this efficiently. This article covers how to pass multiple props concisely and how child components can receive them in style.
1. Basic Approach: Passing Props Individually
The most straightforward method is to explicitly list each prop when using the child component:
function App() {
const headline = "Guide to React Props";
const writer = "DevEnthusiast";
const publishDate = "2025-11-15";
const bodyText = "This article covers passing multiple props...";
return (
<div>
<ArticleCard
title={headline}
author={writer}
date={publishDate}
body={bodyText}
/>
</div>
);
}
The downside is clear: as the number of props grows, the code becomes verbose and error-prone.
2. Concise Approach: Using the Spread Operator
The recommended pattern in React uses the spread operator (...) to "unpack" all properties from an object into individual key-value pairs:
function App() {
const article = {
title: "Guide to React Props",
author: "DevEnthusiast",
date: "2025-11-15",
body: "This article covers passing multiple props..."
};
return (
<div>
{/* Spread operator passes all properties at once */}
<ArticleCard {...article} />
</div>
);
}
How it works: {...article} is equivalent to writing title={article.title} author={article.author} date={article.date} body={article.body}, but much cleaner. This technique is often called "prop spreading" and is a common shorthand in React for reducing boilerplate.
3. Combining Spread with Additional Props
You can spread an object and then add or override specific properties afterward. Properties listed later will overwrite earlier ones:
function App() {
const article = {
title: "Guide to React Props",
author: "DevEnthusiast",
date: "2025-11-15"
};
return (
<div>
<ArticleCard
{...article}
body="This article covers passing multiple props..." // new property
date="2025-11-20" // override existing date
/>
</div>
);
}
This pattern lets you leverage the spread operator for brevity while retaining flexibility for specific adjustments.
Receiving Multiple Props in Child Components
Once props are passed, the child component needs to access them. Using props.propertyName directly works but becomes unwieldy with many props. React recommends destructuring for cleaner prop handling.
1. Basic Approach: Using the Props Object
Props passed to a component arrive as a single object. You can access properties directly via props.propertyName:
function ArticleCard(props) {
return (
<div style={{ border: '1px solid #ddd', padding: '15px', margin: '10px' }}>
<h2>{props.title}</h2>
<p>By: {props.author} | {props.date}</p>
<p>{props.body}</p>
</div>
);
}
This works fine for a handful of props, but writing props. repeatedly becomes repetitive.
2. Elegant Approach 1: Destructuring in Parameters
Object destructuring lets you extract specific properties directly in the function signature:
function ArticleCard({ title, author, date, body }) {
// Use title, author, etc. directly without props.
return (
<div style={{ border: '1px solid #ddd', padding: '15px', margin: '10px' }}>
<h2>{title}</h2>
<p>By: {author} | {date}</p>
<p>{body}</p>
</div>
);
}
Benefits:
- Cleaner code with less repetition
- Immediately visible which props the component expects, improving readability
3. Elegant Approach 2: Destructuring with Default Values
When a prop might not be provided (e.g., date could be missing), you can assign fallback values during destructuring to prevent undefined errors:
function ArticleCard({
title = "Untitled",
author = "Anonymous",
date = "Unknown date",
body = "No content available"
}) {
return (
<div style={{ border: '1px solid #ddd', padding: '15px', margin: '10px' }}>
<h2>{title}</h2>
<p>By: {author} | {date}</p>
<p>{body}</p>
</div>
);
}
When to use: Default values are ideal for optional props, ensuring the component renders gracefully even when data is incomplete.
4. Elegant Approach 3: Nested Destructuring
If props contain nested objects (like user: { name: 'Alice', age: 30 }), you can destructure at multiple levels:
// Parent passes nested object
function App() {
const data = {
title: "Advanced React Patterns",
meta: {
writer: "Alice",
yearsExp: 8
}
};
return <ArticleCard {...data} />;
}
// Child uses nested destructuring
function ArticleCard({
title,
meta: { writer, yearsExp } // extract from nested meta object
}) {
return (
<div>
<h2>{title}</h2>
<p>Author: {writer} ({yearsExp} years experience)</p>
</div>
);
}
// Nested destructuring with defaults for safety
function ArticleCard({
title,
meta: { writer = "Unknown", yearsExp = 0 } = {} // default to empty object
}) {
return <div>Author: {writer}</div>;
}
Caution: When destructuring nested objects, always provide a fallback for the outer object (like = {}) if it might be undefined. Otherwise, you'll encounter a "Cannot destructure property" error.
5. Elegant Approach 4: Collecting Remaining Props
If you only need some props but want to pass the rest along to child elements, use the rest operator (...) to gather unused props:
function ArticleCard({ title, ...remaining }) {
// title is extracted, remaining holds everything else
console.log(remaining); // { author: 'DevEnthusiast', date: '2025-11-15', body: '...' }
return (
<div>
<h2>{title}</h2>
{/* Forward remaining props to an inner element */}
<footer {...remaining} />
</div>
);
}
Use case: When building wrapper components that need to pass native attributes (like onClick, style) to underlying HTML elements or other components.
Complete Example
Bringing everything together:
// Parent: passes props with spread and extra properties
function App() {
const piece = {
title: "React Props Best Practices",
author: "CodeMaster",
// intentionally omitting date to test defaults
body: "A comprehensive guide to handling props in React..."
};
return (
<div>
<h1>Tech Blog</h1>
{/* Spread props and add an extra property */}
<ArticleCard {...piece} estimatedRead="4 min" />
</div>
);
}
// Child: receives props with defaults and rest operator
function ArticleCard({
title = "No Title",
author = "Anonymous",
date = "1970-01-01", // will use default since parent didn't pass it
body = "Empty",
estimatedRead = "1 min",
...extras // capture any additional props
}) {
return (
<div style={{
border: '1px solid #eee',
borderRadius: '8px',
padding: '20px',
margin: '10px 0'
}}>
<h2>{title}</h2>
<div style={{ color: '#666', margin: '10px 0' }}>
{author} | {date} | {estimatedRead}
</div>
<p>{body}</p>
{/* Forward any extra props */}
<section {...extras} />
</div>
);
}
The output displays a complete article card where date falls back to the default "1970-01-01" since the parent didn't provide it, while all other props render normally.
Summary
| Pattern | Use Case |
|---|---|
{...obj} spread |
Pass all properties from an object concisely |
({ a, b, c }) destructuring |
Extract needed props cleanly |
prop = default |
Provide fallbacks for optional props |
Nested obj: { nested } |
Handle nested data structures |
...rest operator |
Collect and forward remaining props |