Props in React
Props in React explains parent-to-child data flow, prop values, destructuring, callbacks, children, composition, immutability, prop drilling, forwarding, and props versus state.
Props — short for properties — are one of the most important concepts in React.
Props allow a parent component to pass data and behavior to a child component.
The simplest mental model is:
Parent Component││ props▼Child Component│▼UI
For example:
function Greeting({ name }) {return <h1>Hello, {name}</h1>;}function App() {return <Greeting name="Jagannath" />;}
Here, App passes the prop name to Greeting.
Learning Objectives
By the end of this lesson, you will understand:
- What props are
- Why props are needed
- Passing props
- Receiving props
- Multiple props
- Props with numbers and booleans
- Props with objects and arrays
- Destructuring props
- Default values
- Passing functions as props
childrenprops- Props and component composition
- One-way data flow
- Props immutability
- Props vs state
- Common mistakes
- Best practices
- Practical examples
- Interview questions
What Are Props?
Props are inputs passed into a React component.
Consider:
<Greeting name="Rahul" />
Here:
Greeting↑name="Rahul"
name is a prop.
The child component can access it:
function Greeting(props) {return <h1>Hello, {props.name}</h1>;}
Props Are Like Function Arguments
This is one of the best ways to understand props.
Normal JavaScript:
function greet(name) {return `Hello, ${name}`;}greet("Rahul");
React:
function Greeting(props) {return <h1>Hello, {props.name}</h1>;}<Greeting name="Rahul" />;
Think:
JavaScript function↓argument↓React component↓props
A component receives props much like a function receives arguments.
Passing a Prop
The parent passes a prop using an attribute-like syntax:
<Greeting name="Rahul" />
Here:
name↓prop name"Rahul"↓prop value
Receiving Props
The child receives an object containing the props.
function Greeting(props) {return (<h1>Hello, {props.name}</h1>);}
If you render:
<Greeting name="Rahul" />
React provides conceptually:
props = {name: "Rahul"};
So:
props.name
returns:
Rahul
Multiple Props
A component can receive many props.
function Student(props) {return (<div><h2>{props.name}</h2><p>{props.course}</p><p>{props.city}</p></div>);}
Use it:
<Studentname="Rahul"course="React"city="Hyderabad"/>
Conceptually:
props = {name: "Rahul",course: "React",city: "Hyderabad"};
Destructuring Props
Instead of:
function Student(props) {return (<div><h2>{props.name}</h2><p>{props.course}</p></div>);}
You can destructure:
function Student({ name, course }) {return (<div><h2>{name}</h2><p>{course}</p></div>);}
This is extremely common in modern React.
Understanding the Destructuring
This:
function Student({ name, course }) {
is essentially shorthand for accessing:
props.nameprops.course
Compare:
function Student(props) {return <h2>{props.name}</h2>;}
with:
function Student({ name }) {return <h2>{name}</h2>;}
Both are valid.
Passing Strings
Strings can be passed directly:
<Greeting name="Rahul" />
The value is a string.
Another example:
<Course title="React Fundamentals" />
Passing Numbers
For numbers, use curly braces:
<Course price={4999} />
Then:
function Course({ price }) {return <p>Price: ₹{price}</p>;}
Result:
Price: ₹4999
Why Curly Braces for Numbers?
Compare:
<Course price="4999" />
and:
<Course price={4999} />
The first passes:
"4999"
as a string.
The second passes:
4999
as a number.
This distinction can matter when performing calculations.
Passing Booleans
You can pass a boolean:
<User isAdmin={true} />
or:
<User isAdmin={false} />
You can also use shorthand:
<User isAdmin />
which is equivalent to:
<User isAdmin={true} />
Using Boolean Props
function User({ isAdmin }) {return (<div>{isAdmin? <p>Administrator</p>: <p>Regular User</p>}</div>);}
Use:
<User isAdmin />
Passing Arrays
Props can contain arrays.
const courses = ["React","JavaScript","Node.js"];function CourseList({ courses }) {return (<ul>{courses.map(course => (<li key={course}>{course}</li>))}</ul>);}
Use:
<CourseList courses={courses} />
Passing Objects
Props can contain objects too.
const user = {name: "Rahul",age: 25,city: "Hyderabad"};
Pass it:
<User user={user} />
Receive it:
function User({ user }) {return (<div><h2>{user.name}</h2><p>{user.age}</p><p>{user.city}</p></div>);}
Passing Objects Directly
You can also write:
<Useruser={{name: "Rahul",age: 25}}/>
Notice the double curly braces:
user={{ ... }}
The outer {} means:
Evaluate JavaScript.
The inner {} is:
A JavaScript object.
Passing Functions as Props
This is a very important React pattern.
A parent can pass a function to a child.
function App() {function handleClick() {console.log("Clicked");}return (<Button onClick={handleClick} />);}
The child:
function Button({ onClick }) {return (<button onClick={onClick}>Click Me</button>);}
The flow is:
App││ onClick function▼Button││ user clicks▼Parent function executes
Why Pass Functions?
This allows a child component to communicate an event back to its parent.
For example:
function App() {function handleDelete() {console.log("Delete requested");}return (<DeleteButtononDelete={handleDelete}/>);}
Child:
function DeleteButton({ onDelete }) {return (<button onClick={onDelete}>Delete</button>);}
The child doesn't need to know what deletion actually does.
It simply says:
The user requested deletion.
The parent decides what happens.
Passing Arguments Through Functions
Suppose the parent has:
function App() {function handleDelete(id) {console.log("Deleting", id);}return (<buttononClick={() => handleDelete(101)}>Delete</button>);}
A child can do the same:
function DeleteButton({ onDelete, id }) {return (<buttononClick={() => onDelete(id)}>Delete</button>);}
Use:
<DeleteButtonid={101}onDelete={handleDelete}/>
Props Are Read-Only
This is one of the most important rules:
A component should not modify its props.
Suppose:
function User({ name }) {// ❌ Don't do thisname = "John";return <h1>{name}</h1>;}
Props should be treated as immutable inputs.
Instead, if the value needs to change, the parent should provide a new prop value, or the component should use its own state where appropriate.
One-Way Data Flow
React follows a primarily one-way data flow model.
Parent││ props▼Child
Data flows downward.
For example:
App↓UserProfile↓Avatar
App can provide data to UserProfile.
UserProfile can provide data to Avatar.
Data Does Not Automatically Flow Up
Suppose:
Parent↓Child
The child cannot simply modify the parent's props.
Instead, the parent can pass a function:
Parent│├── data ↓│└── function ↓│▼Child│└── calls function│▼Parent
This pattern is often called lifting state up when state is moved to a common parent.
Example: Child-to-Parent Communication
function App() {function handleMessage(message) {console.log(message);}return (<ChildonMessage={handleMessage}/>);}
Child:
function Child({ onMessage }) {return (<buttononClick={() =>onMessage("Hello Parent")}>Send Message</button>);}
The child isn't changing parent data directly.
It is invoking a function supplied by the parent.
Props and `children`
One special prop is:
children
For example:
<Card><h2>React</h2><p>Learn React.</p></Card>
The content inside <Card> becomes the children prop.
Receiving `children`
function Card({ children }) {return (<article className="card">{children}</article>);}
This makes the component reusable.
Why `children` Is Powerful
You can create a reusable layout:
function Panel({ children }) {return (<section className="panel">{children}</section>);}
Then:
<Panel><h2>Profile</h2><p>Welcome back.</p></Panel>
Or:
<Panel><CourseList /></Panel>
The Panel doesn't need to know what its content is.
Props Can Contain JSX
Props aren't limited to primitive values.
You can pass JSX:
function Layout({ header }) {return (<div>{header}</div>);}
Use:
<Layoutheader={<h1>My Website</h1>}/>
This is another form of composition.
Props Can Contain Components
You can also pass a component reference.
For example:
function Layout({ Header }) {return (<div><Header /></div>);}
Use:
<Layout Header={MyHeader} />
This pattern is useful in some advanced component architectures.
Default Prop Values
You can provide defaults through JavaScript parameter defaults:
function Greeting({name = "Guest"}) {return (<h1>Hello, {name}</h1>);}
If you write:
<Greeting />
the result is:
Hello, Guest
Default Values With Multiple Props
function ProductCard({name = "Unknown Product",price = 0,inStock = false}) {return (<article><h2>{name}</h2><p>₹{price}</p><p>{inStock? "In Stock": "Out of Stock"}</p></article>);}
Props and State
Props and state are related but different.
Props
Props are:
Passed from parent↓Child receives
State
State belongs to the component:
Component↓Own state
Props vs State
| Props | State |
|---|---|
| Passed into component | Managed by component |
| Read-only from child perspective | Can be updated |
| Usually controlled by parent | Managed by component or other state owner |
| Used to configure components | Used for changing data/UI |
| Flows downward | Changes trigger re-render |
Example:
function Counter({ initialCount }) {const [count, setCount] =useState(initialCount);// ...}
Here:
initialCount → propcount → state
Props Can Initialize State
For example:
function Counter({ initialCount }) {const [count, setCount] =useState(initialCount);return (<buttononClick={() =>setCount(count + 1)}>{count}</button>);}
The parent controls the initial value:
<Counter initialCount={10} />
After initialization, count is local state.
Be careful: changing initialCount later does not automatically mean the existing state should be reset. This distinction is important and will become clearer when learning state and effects.
Props Are Not Automatically State
Suppose:
function User({ name }) {return <h1>{name}</h1>;}
name is a prop.
You don't need:
const [name, setName] = useState(...);
unless the component actually needs independently changing local state.
Don't turn every prop into state unnecessarily.
Prop Drilling
Sometimes data needs to travel through several components.
For example:
App↓Layout↓Sidebar↓UserProfile
If only UserProfile needs the user data, you might have:
<App user={user}><Layout user={user}><Sidebar user={user}><UserProfile user={user} /></Sidebar></Layout></App>
Passing props through components that don't use them is called prop drilling.
Is Prop Drilling Always Bad?
No.
For a small component tree:
Parent↓Child↓Grandchild
passing props explicitly can be the simplest and clearest solution.
You shouldn't introduce Context or another state-management solution just because props pass through two or three components.
When Prop Drilling Becomes a Problem
It can become inconvenient when:
App↓Layout↓Page↓Section↓Card↓Button
and every layer passes the same data even though most layers don't need it.
At that point, alternatives such as Context may be appropriate.
Props and Referential Values
Props can contain objects and functions.
For example:
<Useruser={user}onUpdate={handleUpdate}/>
The values aren't necessarily simple primitives.
This becomes important when studying:
MemoizationReact.memouseMemouseCallback
because object and function references can affect whether components re-render.
Don't worry about optimization yet—first understand basic props.
Props Are Inputs to Rendering
A useful mental model:
Props│▼Functional Component│▼JSX│▼UI
If the parent supplies different props:
New props↓Component renders with new inputs↓UI can change
Example: Dynamic Course Card
Let's create a reusable component.
function CourseCard({title,instructor,price,level}) {return (<article className="course-card"><h2>{title}</h2><p>Instructor: {instructor}</p><p>Level: {level}</p><strong>₹{price}</strong></article>);}
Use it multiple times:
function App() {return (<main><CourseCardtitle="React Fundamentals"instructor="John"price={4999}level="Beginner"/><CourseCardtitle="Advanced React"instructor="Sarah"price={7999}level="Advanced"/></main>);}
Same component.
Different data.
That's one of the major benefits of props.
Props Make Components Reusable
Without props, you might write:
function ReactCourse() {return <h2>React Fundamentals</h2>;}function JavaCourse() {return <h2>Java Fundamentals</h2>;}
With props:
function Course({ title }) {return <h2>{title}</h2>;}
Then:
<Course title="React Fundamentals" /><Course title="Java Fundamentals" />
One component can handle many cases.
Props and Component Configuration
Think of props as configuration.
For example:
<Buttonvariant="primary"size="large"disabled={false}/>
The Button component receives configuration:
variantsizedisabled
and uses those inputs to determine its UI.
A Reusable Button
function Button({children,variant = "primary",disabled = false,onClick}) {return (<buttonclassName={`button ${variant}`}disabled={disabled}onClick={onClick}>{children}</button>);}
Use:
<Button variant="primary">Save</Button>
or:
<Buttonvariant="danger"onClick={handleDelete}>Delete</Button>
This is component design through props.
Props and Composition
Props don't only make components configurable.
They also enable composition.
For example:
function Card({ children }) {return (<div className="card">{children}</div>);}
Now:
<Card><h2>Course</h2><p>React Fundamentals</p></Card>
The parent decides what goes inside the card.
Props Are Data, Not Commands
A good way to think about props:
Props = inputs/configuration
For example:
<Productname="Laptop"price={70000}available/>
These describe the product.
A function prop:
<Product onBuy={handleBuy} />
provides behavior the child can trigger.
Naming Props
Use meaningful names.
Good:
<Username="Rahul"avatarUrl="/avatar.jpg"isAdmin/>
Less clear:
<Userx="Rahul"img="/avatar.jpg"flag/>
Clear prop names make components easier to understand and use.
Boolean Naming
Boolean props often use names that clearly express a condition:
isActiveisLoadingisDisabledhasPermissionshowHeader
For example:
<ButtonisDisabled={true}/>
or, depending on the API:
<Buttondisabled/>
Choose names that clearly communicate meaning.
Avoid Excessive Props
A component with:
<Componenta={...}b={...}c={...}d={...}e={...}f={...}g={...}h={...}i={...}/>
may indicate that the component has too many responsibilities or that its API needs reconsideration.
This isn't an absolute rule—complex components can legitimately have many inputs—but keep component APIs understandable.
Group Related Data When Appropriate
Instead of:
<Username={name}age={age}city={city}avatar={avatar}/>
sometimes an object is appropriate:
<User user={user} />
Then:
function User({ user }) {return (<h2>{user.name}</h2>);}
Neither approach is universally better.
Choose based on clarity and component API design.
Don't Mutate Objects Received Through Props
Suppose:
function User({ user }) {// ❌ Avoiduser.name = "John";return <h2>{user.name}</h2>;}
The child should not mutate an object it received through props.
If data needs to change, use an appropriate state owner and create updated values.
Props and Spread Syntax
You may encounter:
const userProps = {name: "Rahul",age: 25,city: "Hyderabad"};<User {...userProps} />
This passes the object's properties as individual props.
Equivalent conceptually to:
<Username="Rahul"age={25}city="Hyderabad"/>
Receiving Spread Props
You may also see:
function User(props) {return <Profile {...props} />;}
This forwards props.
However, don't use prop spreading everywhere automatically.
Explicit props can make component interfaces easier to understand:
<Profilename={name}age={age}/>
Prop Forwarding
Sometimes a wrapper component forwards certain props:
function Button({ children, ...rest }) {return (<button {...rest}>{children}</button>);}
Now:
<Buttontype="submit"disabled>Save</Button>
The remaining props are forwarded to the <button>.
This is useful for reusable UI components, but should be done intentionally.
Props and DOM Attributes
Be careful when forwarding arbitrary props to DOM elements.
For example, custom component props may not belong on native HTML elements.
A component might receive:
<Button variant="primary" />
You may not want:
<button variant="primary">
unless variant is intentionally represented as a valid attribute/data attribute.
Instead, the component can use variant to determine its class or behavior.
A Complete Example
function ProductCard({name,price,imageUrl,inStock,onBuy}) {return (<article className="product-card"><imgsrc={imageUrl}alt={name}/><h2>{name}</h2><p>₹{price}</p><buttondisabled={!inStock}onClick={onBuy}>{inStock? "Buy Now": "Out of Stock"}</button></article>);}
Parent:
function App() {function handleBuy() {console.log("Product purchased");}return (<ProductCardname="Banarasi Saree"price={4999}imageUrl="/saree.jpg"inStock={true}onBuy={handleBuy}/>);}
Here the props include:
name → stringprice → numberimageUrl → stringinStock → booleanonBuy → function
Complete Data Flow
The example above demonstrates:
App│┌────── ─────┴───────────┐│ │Data Functions│ │└───────────┬───────────┘↓ProductCard│▼JSX│▼UI││ user clicks▼onBuy()│▼App
This is the fundamental React data-flow pattern.
Props vs HTML Attributes
This:
<img src="/logo.png" />
uses an HTML/DOM property.
This:
<User name="Rahul" />
uses a custom component prop.
The syntax looks similar, but React components can define their own APIs through props.
Props vs Parameters
Consider:
function Greeting({ name }) {return <h1>Hello {name}</h1>;}
The function parameter:
{ name }
is derived from the component's props object.
When you write:
<Greeting name="Rahul" />
React supplies the corresponding props.
Props Are Immutable From the Child's Perspective
This phrase is worth remembering:
Props are read-only inputs.
The parent can render:
<Greeting name="Rahul" />
and later:
<Greeting name="Amit" />
The child receives the new value when React renders it with new props.
The child doesn't modify:
props.name
to change the parent.
Common Mistake: Forgetting Curly Braces for Variables
Suppose:
const name = "Rahul";
Incorrect:
<Greeting name="name" />
This passes the literal string:
"name"
Correct:
<Greeting name={name} />
This passes:
"Rahul"
Common Mistake: Passing a Number as a String
Incorrect if you need a number:
<Course price="4999" />
Correct:
<Course price={4999} />
Otherwise:
price + 100
may behave differently because the value is a string.
Common Mistake: Mutating Props
Avoid:
function User({ user }) {user.name = "John";}
Treat props as immutable.
Common Mistake: Turning Every Prop Into State
Avoid unnecessarily doing:
function User({ name }) {const [userName, setUserName] =useState(name);return <h1>{userName}</h1>;}
If you simply need to display the prop:
function User({ name }) {return <h1>{name}</h1>;}
is better.
Common Mistake: Passing the Result Instead of the Function
Suppose:
function handleClick() {console.log("Clicked");}
Usually:
<Button onClick={handleClick} />
Not:
<Button onClick={handleClick()} />
The latter executes the function during rendering.
Common Mistake: Confusing `children`
Given:
<Card><h2>Hello</h2></Card>
the child content is available as:
function Card({ children }) {return children;}
It isn't a prop named content unless you explicitly pass:
<Card content={<h2>Hello</h2>} />
Best Practices
1. Treat props as read-only.
2. Give props meaningful names.
3. Keep component APIs understandable.
4. Use destructuring when it improves readability.
5. Don't duplicate props into state unnecessarily.
6. Use function props for child-to-parent communication.
7. Use children for composition.
8. Keep data flow explicit.
9. Avoid unnecessary prop drilling.
10. Don't optimize props prematurely.
Practical Exercise
Create a:
StudentCard
component that accepts:
namecourseprogressisActive
Usage:
<StudentCardname="Rahul"course="React"progress={75}isActive={true}/>
Display:
RahulReactProgress: 75%Active
Solution
function StudentCard({name,course,progress,isActive}) {return (<article><h2>{name}</h2><p>Course: {course}</p><p>Progress: {progress}%</p><p>{isActive? "Active": "Inactive"}</p></article>);}
Advanced Exercise: Child-to-Parent Communication
Create:
StudentCard
with:
nameonEnroll
Parent:
function App() {function handleEnroll(name) {console.log(`${name} enrolled`);}return (<StudentCardname="Rahul"onEnroll={handleEnroll}/>);}
Child:
function StudentCard({name,onEnroll}) {return (<article><h2>{name}</h2><buttononClick={() => onEnroll(name)}>Enroll</button></article>);}
The flow is:
App││ name + onEnroll▼StudentCard││ click▼onEnroll(name)│▼App
This pattern is fundamental to React.
Interview questions & answers
Interview preparation
6 questions grouped by difficulty — expand any card for a model answer and follow-up probe.
Beginner
1What Are Props?
BeginnerModel answer
Props, short for properties, are read-only inputs passed from a parent component to a child component.
They allow components to receive data, configuration, JSX, and functions, making components reusable and composable.
2Are Props Mutable?
BeginnerModel answer
Props should be treated as immutable by the receiving component.
A child should not modify its props.
If data needs to change, the appropriate state owner should update the data and pass the new value through props.
Intermediate
3How Does Data Flow in React?
IntermediateModel answer
React primarily follows one-way data flow.
Data generally flows from parent components to children through props.
When a child needs to trigger a change in parent-owned data, the parent can pass a callback function to the child.
4Can You Pass Functions Through Props?
IntermediateModel answer
Yes.
A parent can pass a function to a child as a prop, and the child can invoke it in response to an interaction.
This is a standard pattern for child-to-parent communication.
5What Is children?
IntermediateModel answer
children is a special prop containing the JSX or content nested between a component's opening and closing tags.
It enables reusable wrapper and layout components.
Advanced
6Props vs State?
AdvancedModel answer
Props are inputs supplied to a component, typically from its parent, and should be treated as read-only by the receiving component.
State is data managed by a component or another state owner and can change over time.
Changes to state or props can cause React to render updated UI.
The Most Important Mental Model
Think about every React component like a function:
Props│▼┌─────────────────┐│ Component ││ ││ Logic │└────────┬────────┘│▼JSX│▼UI
For example:
function CourseCard({title,price}) {return (<article><h2>{title}</h2><p>₹{price}</p></article>);}
Then:
<CourseCardtitle="React"price={4999}/>
Think:
title = "React"price = 4999↓CourseCard↓JSX↓UI
Final Cheat Sheet
Pass a string
<Greeting name="Rahul" />
Pass a number
<Course price={4999} />
Pass a boolean
<User isAdmin />
Pass an array
<List items={items} />
Pass an object
<User user={user} />
Pass a function
<Button onClick={handleClick} />
Receive props
function User(props) {return <h1>{props.name}</h1>;}
Destructure props
function User({ name }) {return <h1>{name}</h1>;}
Default value
function User({ name = "Guest" }) {return <h1>{name}</h1>;}
Children
function Card({ children }) {return <div>{children}</div>;}
Don't mutate props
// ❌props.name = "John";
The central idea of Props is:
Props allow a parent component to provide data and behavior to a child component, making components reusable, configurable, and composable.
The fundamental React flow is:
PARENT││ Props▼CHILD││ renders▼UI
And for interactions:
PARENT│data + callback▼CHILD│user interacts│▼callback()│▼PARENT
If you understand props + JSX + functional components, you now have the core building blocks needed to start understanding state, events, and component communication in modern React.