What Are React Props?
Props (short for "properties") are the primary mechanism for passing data between React components. Every parent component can pass information to its child components by giving them props. Unlike HTML attributes, props can carry any JavaScript value including objects, arrays, and functions.
Props work alongside JSX to create a powerful composition system where components remain reusable and independent. By separating configuration from implementation, you build applications that are easier to test, maintain, and scale.
Key Characteristics of Props
- Immutable: Props cannot be modified by the receiving component
- One-way data flow: Data flows from parent to child only
- Composable: Components can be reused with different prop values
- Flexible: Can pass any JavaScript value type
Props are to React components what arguments are to functions -- they configure and customize component behavior without the component needing to know where that configuration comes from.
Passing Props to Components
Passing props to child components follows a syntax similar to HTML attributes, but with the flexibility to pass any JavaScript value.
Basic Prop Passing
function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}
- String props use quotes:
title="My Title" - Other JavaScript values use curly braces:
size={100} - Object props require double curly braces:
person={{ name: 'Lin' }}
Reading Props in Components
React components receive props as their first argument. Use destructuring to extract the values you need:
function Avatar({ person, size }) {
return (
<img
src={getImageUrl(person)}
alt={person.name}
width={size}
height={size}
/>
);
}
Default Prop Values
Set default values to ensure components render gracefully when props aren't provided. The modern approach uses destructuring defaults:
function Avatar({ person, size = 100 }) {
// size defaults to 100 if not provided by the parent
return <img src={person.image} width={size} />;
}
When to Use Defaults
- Optional styling props (className, variant)
- Optional configuration (size, timeout)
- Props with sensible fallbacks (pagination size, theme mode)
- Props that enhance but aren't essential to functionality
The Children Prop: Flexible Component Composition
The special children prop captures any JSX passed between a component's opening and closing tags, enabling powerful composition patterns. This pattern is essential for building reusable layout components and wrapper elements that adapt to any content.
How Children Work
function Card({ children }) {
return <div className="card">{children}</div>;
}
function App() {
return (
<Card>
<h2>Card Title</h2>
<p>This content becomes the children prop.</p>
</Card>
);
}
Common Use Cases
- Layout components: Wrappers that add styling or structure
- Modal dialogs: Content container with overlay
- Card components: Titled content areas
- Provider components: Context wrappers
For complex composition patterns, see how React Hooks can enhance component logic and state management alongside props.
1// TypeScript Prop Types for Better Developer Experience2 3interface AvatarProps {4 person: {5 name: string;6 imageId: string;7 };8 size?: number; // Optional prop9 className?: string; // Optional prop10}11 12function Avatar({ person, size = 100, className }: AvatarProps) {13 return (14 <img 15 className={className} 16 src={`/images/${person.imageId}.jpg`} 17 alt={person.name}18 width={size} 19 height={size} 20 />21 );22}Performance Considerations with Props
Props directly impact component re-renders. Understanding these patterns helps you build performant applications that scale efficiently.
Memoization to Prevent Unnecessary Re-renders
import { memo } from 'react';
const Avatar = memo(function Avatar({ person, size }) {
return <img src={person.image} width={size} />;
});
Stable Object References
Inline objects create new references on each render, which can defeat memoization:
// ❌ Bad: New object on every render
<Avatar person={{ name: 'Lin', image: '1bX5QH6' }} size={100} />
// ✅ Good: Stable reference
const defaultPerson = { name: 'Lin', image: '1bX5QH6' };
<Avatar person={defaultPerson} size={100} />
Best Practices
- Use primitive values when possible
- Memoize components that receive object/array props
- Keep prop objects flat and simple
- Consider component composition to reduce prop drilling
Our web development services team specializes in optimizing React applications for maximum performance and scalability.
Common Props Patterns
Callback Props (Parent-Child Communication)
Pass functions as props to enable child components to communicate back to parents:
function TodoList({ todos, onToggle, onDelete }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
<span onClick={() => onToggle(todo.id)}>
{todo.text}
</span>
<button onClick={() => onDelete(todo.id)}>Delete</button>
</li>
))}
</ul>
);
}
Spread Operator for Props
Use sparingly -- explicit props are clearer:
function Profile({ name, age, ...rest }) {
return <Avatar {...rest} />; // Passes all other props to Avatar
}
Configuration Objects
For complex configurations, group related props:
// Instead of many individual props
<Button variant="primary" size="lg" disabled={false} />
// Use a configuration object
<Button config={{ variant: 'primary', size: 'lg', disabled: false }} />
Keep Props Simple
Pass primitives when possible. Avoid deeply nested objects that make components harder to understand and test.
Document Your Props
Use TypeScript interfaces or PropTypes for clear contracts. Document what each prop does and its expected format.
Use Descriptive Names
Make prop purpose clear from the name. Use onPrefix for events (onClick, onSubmit) and descriptive names for data.
Provide Sensible Defaults
Always consider what happens when props aren't provided. Defaults prevent crashes and improve reusability.
Avoid Prop Drilling
For deeply nested data access, use composition or React Context instead of passing props through many layers.
Type Your Props
TypeScript provides better developer experience through autocomplete, type checking, and error detection at compile time.