Props are how components communicate. A parent passes data down to a child through props. Here's how to use them effectively.
Passing different types
JSX
function ProductCard({ name, price, inStock, tags, onBuy }) {
return (
<div>
<h3>{name}</h3>
<p>NPR {price}</p>
{inStock ? <span>In stock</span> : <span>Out of stock</span>}
{tags && tags.map(tag => <span key={tag}>{tag}</span>)}
<button onClick={onBuy}>Buy</button>
</div>
);
}
<ProductCard
name="Notebook"
price={150}
inStock={true}
tags={['stationery', 'school']}
onBuy={() => alert('Bought!')}
/>Props as render props
JSX
function DataFetcher({ url, children }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => { setData(data); setLoading(false); });
}, [url]);
if (loading) return <p>Loading...</p>;
return children(data);
}
// Usage
<DataFetcher url="/api/users">
{(users) => (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
)}
</DataFetcher>Extracting props
JSX
// ❌ Passing too many props
<UserCard name="Ram" age={22} role="student" email="ram@example.com"
phone="9841234567" city="Kathmandu" />
// ✅ Pass an object instead
const user = { name: "Ram", age: 22, role: "student" };
<UserCard {...user} /> // spread operatorProp drilling problem
When you need to pass props through many layers of components, it becomes tedious. React's Context API and state management libraries (Zustand, Redux) solve this — but start with props and only reach for those when prop drilling becomes a real problem.
Tips
- Name props descriptively —
isLoadingis better thanflag. - Use
childrenfor composition patterns. - Destructure props in the function signature for cleaner code.
- Keep the prop interface simple — if a component has 10+ props, split it up.
Next: state.