React Props & State

Pass data with props, manage change with state, and flow data between components

Props useState Lifting State Data Flow

Table of Contents

1. Introduction: Understanding Data in React

Every React application needs to manage data. React provides two main ways to handle data:

ConceptPurposeAnalogy
PropsPass data from parent to child (read-only)A gift with a "do not open until Christmas" label
StateData that changes over time within a componentA whiteboard you can write on and erase

Golden Rule: Props are passed down. State is managed within.

2. What are Props?

Props (short for "properties") are read-only inputs passed from a parent component to a child component.

2.1 Passing Props to Components

JSXfunction Parent() { return ( <Child name="Alice" age={25} isLoggedIn={true} colors={["red", "blue"]} user={{ id: 1, role: "admin" }} /> ); }

2.2 Accessing Props in Functional Components

JSXfunction Child(props) { return <h1>Hello, {props.name}!</h1>; } function Child({ name, age, isLoggedIn }) { return ( <div> <h1>Hello, {name}!</h1> <p>Age: {age}</p> <p>Status: {isLoggedIn ? "Logged In" : "Logged Out"}</p> </div> ); }

2.3 Accessing Props in Class Components

JSXclass Child extends React.Component { render() { return ( <div> <h1>Hello, {this.props.name}!</h1> <p>Age: {this.props.age}</p> </div> ); } }

2.4 Props are Read-Only (Immutability)

You cannot modify props inside a child component.

JSX// WRONG function Child({ name }) { name = "Bob"; // Cannot reassign props return <h1>{name}</h1>; } // CORRECT function Child({ name }) { return <h1>{name}</h1>; }

2.5 Default Props and PropTypes

JSXimport PropTypes from 'prop-types'; function Greeting({ name, age }) { return <h1>{name} is {age} years old</h1>; } Greeting.defaultProps = { name: "Guest", age: 18 }; Greeting.propTypes = { name: PropTypes.string, age: PropTypes.number.isRequired }; <Greeting age={25} /> // name defaults to "Guest"

2.6 Destructuring Props

JSXfunction User({ user, role }) { const { name, email } = user; return ( <div> <p>Name: {name}</p> <p>Email: {email}</p> <p>Role: {role}</p> </div> ); }

2.7 children Prop (Nested Content)

JSXfunction Card({ title, children }) { return ( <div className="card"> <h2>{title}</h2> <div className="card-content">{children}</div> </div> ); } <Card title="Welcome"> <p>This content is passed as children prop</p> <button>Click Me</button> </Card>

3. What is State?

State is data that is private to a component and can change over time. When state changes, React re-renders the component.

3.1 State vs Props: The Key Difference

AspectPropsState
OwnershipOwned by parentOwned by the component itself
MutabilityImmutableMutable (via setter)
PurposePass data parent → childTrack changing internal data
Who can change?Only the parentThe component itself
Trigger re-render?Yes, when props changeYes, when state changes
JSX// Props — data flows DOWN <Child message="Hello" /> // State — data is INTERNAL function Counter() { const [count, setCount] = useState(0); return <button onClick={() => setCount(count + 1)}>{count}</button>; }

3.2 State in Functional Components (useState Hook)

JSXimport { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); const [name, setName] = useState(""); const [isActive, setIsActive] = useState(false); const [user, setUser] = useState({ id: 1, name: "John" }); const [items, setItems] = useState([]); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }

Multiple useState calls for separate pieces of state (email, password, errors in a form).

3.3 State in Class Components (this.state)

JSXclass Counter extends React.Component { state = { count: 0, name: "", user: { id: 1, name: "John" } }; increment = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.increment}>Increment</button> </div> ); } }

3.4 When to Use State vs Props

Use State When...Use Props When...
Data changes over time (input, API)Data is static or from parent
Data is private to the componentData shared with child components
Track internal component dataReusable component with different configs
JSX// Good: input uses state function SearchBox() { const [query, setQuery] = useState(""); return <input value={query} onChange={(e) => setQuery(e.target.value)} />; } // Good: display uses props function DisplayName({ name }) { return <h1>{name}</h1>; }

4. State Updates in React

4.1 Never Mutate State Directly

JSX// WRONG count = count + 1; // React won't re-render // CORRECT setCount(count + 1);

4.2 setState is Asynchronous

JSXsetCount(count + 1); console.log(count); // Still the OLD value! useEffect(() => { console.log("Count updated to:", count); }, [count]);

4.3 Functional Updates (When New State Depends on Previous State)

JSX// PROBLEM: both use stale count — only +1 setCount(count + 1); setCount(count + 1); // SOLUTION: functional update — +2 setCount(prev => prev + 1); setCount(prev => prev + 1);

Use functional updates when: multiple updates in one function, new state depends on previous, or inside useEffect with empty deps.

4.4 Object State Updates (Merging and Spreading)

JSX// WRONG user.age = 26; setUser(user); // CORRECT setUser({ ...user, age: 26 }); setUser(prev => ({ ...prev, age: prev.age + 1, isActive: true })); // Nested update setState(prev => ({ ...prev, user: { ...prev.user, address: { ...prev.user.address, city: "Delhi" } } }));

4.5 Array State Updates (Adding, Removing, Updating Items)

JSX// ADD setItems([...items, newItem]); setItems([newItem, ...items]); // REMOVE setItems(items.filter(item => item.id !== idToRemove)); // UPDATE setItems(items.map(item => item.id === idToUpdate ? { ...item, completed: true } : item )); // WRONG — direct mutation items.push(newItem); setItems(items);

4.6 Batching of State Updates

React batches state updates in the same synchronous event handler — only one re-render at the end. In React 18+, updates in promises and timeouts are also batched.

JSXconst handleSubmit = () => { setName("John"); setAge(25); setEmail("john@example.com"); // Only 1 re-render };

5. Passing Data Between Components

5.1 Parent to Child (via Props) – One-Way Data Flow

JSXfunction App() { const [user, setUser] = useState({ name: "Alice", role: "Admin" }); return ( <div> <Profile user={user} /> <Dashboard role={user.role} /> </div> ); } function Profile({ user }) { return <h1>Welcome, {user.name}!</h1>; }

5.2 Child to Parent (via Callback Functions)

JSXfunction Parent() { const [dataFromChild, setDataFromChild] = useState(""); const handleChildData = (childData) => setDataFromChild(childData); return ( <div> <p>Data from child: {dataFromChild}</p> <Child onSendData={handleChildData} /> </div> ); } function Child({ onSendData }) { return <button onClick={() => onSendData("Hello from Child!")}>Send</button>; }

5.3 Sibling to Sibling (Lifting State Up)

Lift state to the closest common ancestor when siblings need to share data.

JSXfunction App() { const [selectedItem, setSelectedItem] = useState(null); return ( <div> <ItemList onSelectItem={setSelectedItem} /> <ItemDetails item={selectedItem} /> </div> ); }

5.4 Distant Components (Context API) – Overview

JSXconst UserContext = React.createContext(); function App() { const [user, setUser] = useState({ name: "Alice", role: "Admin" }); return ( <UserContext.Provider value={{ user, setUser }}> <DeeplyNestedComponent /> </UserContext.Provider> ); } function DeeplyNestedComponent() { const { user } = useContext(UserContext); return <h1>Hello, {user.name}</h1>; }

5.5 Component Composition (Alternative to Prop Drilling)

JSX// GOOD: pass components, not props through levels function App() { const [user, setUser] = useState({ name: "Alice" }); return ( <Layout header={<UserHeader user={user} />} content={<UserContent user={user} />} /> ); } function Layout({ header, content }) { return <div><div className="header">{header}</div><div>{content}</div></div>; }

6. Complete Working Examples

6.1 Example 1: Todo App (Props + State + Lifting State Up)

JSXfunction App() { const [todos, setTodos] = useState([]); const addTodo = (text) => { setTodos([...todos, { id: Date.now(), text, completed: false }]); }; const toggleTodo = (id) => { setTodos(todos.map(t => t.id === id ? { ...t, completed: !t.completed } : t)); }; const deleteTodo = (id) => setTodos(todos.filter(t => t.id !== id)); return ( <div> <h1>My Todo App</h1> <TodoForm onAdd={addTodo} /> <TodoList todos={todos} onToggle={toggleTodo} onDelete={deleteTodo} /> </div> ); } function TodoForm({ onAdd }) { const [input, setInput] = useState(""); const handleSubmit = (e) => { e.preventDefault(); if (input.trim()) { onAdd(input); setInput(""); } }; return ( <form onSubmit={handleSubmit}> <input value={input} onChange={(e) => setInput(e.target.value)} /> <button type="submit">Add</button> </form> ); } function TodoItem({ todo, onToggle, onDelete }) { return ( <li style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}> <input type="checkbox" checked={todo.completed} onChange={() => onToggle(todo.id)} /> {todo.text} <button onClick={() => onDelete(todo.id)}>Delete</button> </li> ); }

6.2 Example 2: User Profile Dashboard

JSXfunction App() { const [user, setUser] = useState({ name: "John Doe", email: "john@example.com", age: 28, isActive: true }); const updateUser = (updates) => setUser(prev => ({ ...prev, ...updates })); return ( <div> <ProfileCard user={user} /> <EditForm user={user} onUpdate={updateUser} /> <ActivityStatus isActive={user.isActive} /> </div> ); } function EditForm({ user, onUpdate }) { const [formData, setFormData] = useState(user); const handleChange = (e) => { const { name, value, type, checked } = e.target; setFormData(prev => ({ ...prev, [name]: type === 'checkbox' ? checked : value })); }; const handleSubmit = (e) => { e.preventDefault(); onUpdate(formData); }; return ( <form onSubmit={handleSubmit}> <input name="name" value={formData.name} onChange={handleChange} /> <input name="email" value={formData.email} onChange={handleChange} /> <button type="submit">Save</button> </form> ); }

7. Common Mistakes and Best Practices

MistakeWhy It's WrongCorrect Way
Mutating state directlyReact won't re-renderUse setter with new object/array
Calling setState in a loopMultiple re-rendersCollect updates, apply once
Using state right after setStatesetState is asyncUse useEffect or functional updates
Not using functional updatesStale closure bugssetCount(prev => prev + 1)
State for derived dataWastes memoryCompute: count % 2 === 0
One giant state objectHard to updateSplit into multiple useState
JSX// DO const [count, setCount] = useState(0); setCount(prev => prev + 1); setUser({ ...user, age: user.age + 1 }); const completedCount = todos.filter(t => t.completed).length; // DON'T state.count = 5; setState(state);

8. Summary Cheat Sheet

JSX// PROPS <Child name="Alice" age={25} /> function Child({ name, age }) { return <div>{name}</div>; } function Card({ children }) { return <div>{children}</div>; } // STATE const [value, setValue] = useState(initialValue); setValue(newValue); setValue(prev => prev + 1); // Object / Array setUser({ ...user, name: "John" }); setItems([...items, newItem]); setItems(items.filter(i => i.id !== id)); // DATA FLOW // Parent → Child: props // Child → Parent: callback prop // Siblings: lift state to parent

Next Steps

  • Event Handling – onClick, onChange, onSubmit
  • Forms in React – Controlled vs uncontrolled components
  • useEffect Deep Dive – Side effects, API calls
  • Context API – Avoid prop drilling
  • useReducer Hook – Complex state logic

React Props & State MCQ Practice

10 Basic MCQs 10 Advanced MCQs

10 Basic React Props & State MCQs

1

Props in React are:

ARead-only data from parent to child
BMutable local variables
CGlobal CSS classes
DRouter paths only
Explanation: Children should not modify props directly.
2

State is used when:

AData changes inside a component over time
BPassing data from child to parent only
CStyling with Tailwind only
DInstalling npm packages
Explanation: State triggers re-renders when updated.
3

useState returns:

ACurrent value and updater function
BOnly a DOM node
CA Promise
Dprops object
Explanation: Destructuring: const [x, setX] = useState(0).
4

Updating state correctly:

ACall the setter function setCount(1)
BMutate count = 1 directly
CEdit props.title
DChange DOM innerHTML only
Explanation: Direct mutation does not trigger re-renders.
5

Props flow direction is:

AParent to child
BChild to parent only
CRandom
DFrom CSS to JSX
Explanation: One-way data flow down the tree.
6

Default props can be set with:

ADefault parameters or defaultProps
BDeleting state
CuseEffect only
DlocalStorage only
Explanation: Function params: function Button({ label = 'Click' }).
7

Lifting state up means:

AMove shared state to common ancestor
BDelete all state
CUse only refs
DStore in window
Explanation: Siblings share data via parent props.
8

Props are accessed in a function component via:

AFunction parameters
Bthis.props only
Cdocument.getElementById
Dimport.meta
Explanation: function Greeting({ name }).
9

Calling setState with same primitive value:

AMay bail out of re-render in React 18+
BAlways reloads page
CThrows error
DUpdates props
Explanation: React compares with Object.is for primitives.
10

Immutable state update for objects means:

ASpread previous state: setUser({...user, name})
Buser.name = 'x' only
CDelete user
DUse innerHTML
Explanation: Create new object/array references.

10 Advanced React Props & State MCQs

1

Stale closure in useState often happens when:

AEvent handler captures old state without functional update
BUsing too many components
CJSX is invalid
Dnpm is outdated
Explanation: Use setCount(c => c + 1) when next state depends on previous.
2

Batching in React 18 means:

AMultiple setStates in same event may cause one re-render
BEach setState always reloads page
CState updates are synchronous in DOM always
DProps become mutable
Explanation: Automatic batching improves performance.
3

Prop drilling refers to:

APassing props through many intermediate layers
BUsing Context always
CServer-side rendering
DCSS modules
Explanation: Context or composition can reduce drilling.
4

Derived state anti-pattern is:

ACopying props into state without need
BUsing useMemo for calculations
CLifting state up
DUsing keys in lists
Explanation: Prefer computing from props during render when possible.
5

Shallow merge with setState for objects in useState:

AReplace entire object unless you spread previous
BDeep merge automatically
CMutate nested fields safely
DProps update automatically
Explanation: useState does not deep-merge objects.
6

Children as function pattern (render props) passes:

AA function child that receives data from parent
BOnly CSS classes
CRouter config
DRedux store
Explanation: Parent calls children(data) to share logic.
7

key prop on component at same level helps:

APreserve identity when reordering lists
BStyle buttons
CEnable npm
DReplace useState
Explanation: Keys affect reconciliation of component state.
8

Controlled vs state: input value tied to state is:

AControlled component
BUncontrolled
CServer component
DStatic HTML only
Explanation: value + onChange sync with React state.
9

useReducer is preferable when:

AState logic is complex with multiple sub-values
BNo state needed
COnly CSS changes
DInstalling packages
Explanation: Reducer centralizes transition logic.
10

Passing callbacks via props allows child to:

ANotify parent without mutating parent props
BMutate parent state directly
CSkip rendering
DAccess database
Explanation: onSave={handleSave} is common pattern.

15 React Props & State Interview Questions & Answers

Easy Medium Hard
1What is the difference between props and state?easy
Answer: Props are read-only inputs from parent; state is internal mutable data managed by the component.
2Can you modify props inside a child?easy
Answer: No—props are immutable; request changes via callback props to parent.
3How do you update state from an event handler?easy
Answer: Call the setter from useState, e.g. setCount(count + 1).
4What is lifting state up?medium
Answer: Moving shared state to the closest common ancestor and passing it down as props.
5Why avoid mutating state directly?medium
Answer: React compares references; mutation skips re-render and breaks predictability.
6What is prop drilling?medium
Answer: Passing data through many layers of components that do not need the data.
7When use functional setState?medium
Answer: When new state depends on previous state to avoid stale closures.
8What are default props?easy
Answer: Fallback values when parent does not pass a prop.
9Can state hold objects and arrays?medium
Answer: Yes—always replace with new references when updating nested data.
10How does parent receive data from child?medium
Answer: Pass a callback prop like onChange={handleChange} for child to invoke.
11What is one-way data flow?medium
Answer: Data flows down via props; events flow up via callbacks.
12useState vs useReducer?hard
Answer: useState for simple values; useReducer for complex state transitions.
13What causes stale state in hooks?hard
Answer: Closures capturing old state—fix with functional updates or correct deps.
14Are props available in useEffect dependency array?medium
Answer: Yes—when effects should re-run if a prop changes.
15Explain batching.hard
Answer: React groups multiple state updates into one render for performance.