Props in Depth

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 operator

Prop 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 — isLoading is better than flag.
  • Use children for 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.