ForgeFrontend — Prepare, Practice, Crack
Secure checkout
Lifetime access
Instant PDF download
Free updates forever

Prepare · Practice · Crack

Props vs State in React

Short answer

Props are data passed into a component from its parent. The component can read them but never change them. State is data the component owns and controls, and updating it re-renders the component. Both trigger a re-render when they change — the difference is who is allowed to change them.

PropsState
Owned byThe parentThe component itself
Can the component change it?No — read-onlyYes, via the setter
Changing it re-rendersYes, when the parent re-rendersYes
Set initially byWhoever renders the componentuseState / useReducer
Passed down the treeYes, that is the pointOnly by passing it as a prop
Available in the component bodyAs function argumentsFrom the hook
Typical examplesuserId, label, onClick, childrenisOpen, inputValue, fetchedData
One question answers most of it: who owns this value?

What each one actually is

A React component is a function that takes data and returns what should be on screen. Props are that function's arguments — supplied by whoever renders the component, and like any function's arguments, they belong to the caller. State is a value the component keeps for itself between calls, which is exactly what a plain function cannot do and what the useState hook adds.

Both in one componentjsx
1function Counter({ label, step }) {        // props: given by the parent
2  const [count, setCount] = useState(0);   // state: owned here
3
4  return (
5    <button onClick={() => setCount(count + step)}>
6      {label}: {count}
7    </button>
8  );
9}
10
11<Counter label="Likes" step={1} />
12// → renders "Likes: 0", and clicking gives "Likes: 1", "Likes: 2"13// label and step never change from inside Counter.
14// count only ever changes from inside Counter.

That component cannot change its own label. If the label needs to change, the parent changes it — probably from the parent's own state — and passes down a new value. This is what people mean when they say React data flow is one-way: data moves down through props, and changes move up through callbacks.

"Read-only" is stricter than it sounds

Props are immutable from the child's point of view, and React does not stop you from breaking that rule — it simply produces confusing behaviour when you do. Mutating a prop object mutates the parent's data, because objects are passed by reference. The change does not trigger a render, so the screen and the data drift apart, and the eventual re-render appears to come from nowhere.

Mutating props: the bug and the fixjsx
1function Profile({ user }) {
2  user.name = user.name.trim();     // → mutates the PARENT's object
3  return <h1>{user.name}</h1>;
4  // Nothing re-renders. Other components reading the same object now
5  // disagree with what is on screen until something unrelated renders.
6}
7
8// Fix 1 — derive during render, change nothing
9function Profile({ user }) {
10  const name = user.name.trim();
11  return <h1>{name}</h1>;
12}
13
14// Fix 2 — if it must persist, the PARENT owns the change
15function Parent() {
16  const [user, setUser] = useState({ name: " Arun " });
17  const clean = () => setUser(u => ({ ...u, name: u.name.trim() }));
18  // → new object, new reference, React re-renders
19}

The same rule applies to state, and it is the more common version of this mistake. `state.items.push(x)` followed by `setItems(state.items)` does nothing visible, because the array reference has not changed and React compares by identity. You must produce a new array or object every time.

Deciding where a value belongs

Most component design questions reduce to placing a value correctly, and there is a reliable three-question test. Does it change over time? If not, it is a constant or a prop, not state. Can it be calculated from existing props or state? If so, calculate it during render — do not store it. Does anything else need it? If so, it belongs higher up and arrives as a prop.

Derived values are not statejsx
1// Wrong — a second source of truth that must be kept in sync
2function Cart({ items }) {
3  const [total, setTotal] = useState(0);
4  useEffect(() => {
5    setTotal(items.reduce((s, i) => s + i.price, 0));
6  }, [items]);
7  // → renders once with a stale 0, then again with the real total
8}
9
10// Right — one source of truth, computed on the way past
11function Cart({ items }) {
12  const total = items.reduce((s, i) => s + i.price, 0);
13  return <p>₹{total}</p>;
14  // → correct on the very first render, and impossible to desynchronise
15}

That extra render is not the main cost. The real cost is that two values now have to agree, and every future change to `items` is an opportunity for them to stop agreeing. Deriving during render makes the bug unrepresentable, which is worth far more than the render you saved.

This is 1 of 75+ questions in the React Interview Kit

Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.

⚡ Get the React Interview Kit → ₹399

Lifting state up

When two sibling components need the same value, neither can own it. The value moves to their closest common parent, which passes it down as a prop to both and passes down a setter to whichever one needs to change it. This is the standard React answer to "how do these two components talk to each other", and being able to describe it precisely is worth more than knowing any state library.

The pattern, end to endjsx
1function Filters() {
2  const [query, setQuery] = useState("");   // lifted: both children need it
3
4  return (
5    <>
6      <SearchInput value={query} onChange={setQuery} />
7      <ResultCount query={query} />
8    </>
9  );
10}
11
12function SearchInput({ value, onChange }) {
13  return <input value={value} onChange={e => onChange(e.target.value)} />;
14  // → owns nothing; reports upward
15}
16
17function ResultCount({ query }) {
18  return <p>{search(query).length} results</p>;
19  // → reads only
20}

SearchInput has become a controlled component: its displayed value comes from a prop and its changes go out through a callback. That is the same props-and-state split applied to form inputs, which is why controlled versus uncontrolled inputs is really this question in a different costume.

Props are not constant — they just are not yours

A common misreading is that props never change. They change all the time; what is fixed is that the change comes from outside. When a parent re-renders with a new value, the child receives it as a new prop and re-renders with it. Within a single render the props are frozen, which is what makes a component predictable.

The same child, receiving three different props over timejsx
1function Parent() {
2  const [theme, setTheme] = useState("dark");
3  return (
4    <>
5      <button onClick={() => setTheme(t => t === "dark" ? "light" : "dark")}>
6        Toggle
7      </button>
8      <Panel theme={theme} />
9    </>
10  );
11}
12
13function Panel({ theme }) {
14  return <div className={theme}></div>;
15  // → theme is "dark", then "light", then "dark"
16  //   Panel never changed it; the parent's state did.
17}
The key trick, which is the fix most people never learnjsx
1// Modal keeps showing the last user's name, because state was
2// initialised from the prop on the first mount only.
3<EditForm user={selected} />
4
5// Changing the key makes React discard the old component and mount a
6// fresh one, so useState re-initialises with the new prop.
7<EditForm key={selected.id} user={selected} />
8// → state resets exactly when the identity of the data changes

children and callbacks are props too

It is easy to think of props as configuration values, but anything you pass through JSX is a prop — including functions and other elements. `children` is a prop React fills in from whatever you nest inside the tags, and event handlers are ordinary function props. Understanding that unlocks composition patterns that otherwise look like framework magic.

Three kinds of prop, one mechanismjsx
1function Card({ title, onDismiss, children }) {
2  return (
3    <section>
4      <h2>{title}</h2>          {/* a value */}
5      <button onClick={onDismiss}>×</button>   {/* a function */}
6      {children}                {/* elements passed by the caller */}
7    </section>
8  );
9}
10
11<Card title="Order #1041" onDismiss={() => setOpen(false)}>
12  <p>Shipped to Chennai</p>
13</Card>
14// → children is the <p>, and Card renders it without knowing what it is

The callback prop is how a child changes something it does not own. It does not modify the prop; it calls a function the parent supplied, and the parent updates its own state. Data down, events up — that is the whole contract, and it is why React apps stay traceable as they grow.

Where context and stores fit

Props are explicit, which is their strength and their limit. Passing a value through five layers to reach one deep component — prop drilling — makes every layer in between depend on data it does not use. Context solves the delivery problem, not the ownership problem: the value is still state, owned by whoever holds it, just delivered without the intermediate stops.

ScopeUseNotes
One componentuseStateThe default; start here
Parent and its childrenuseState + propsLifting state up
Deep subtree, changes rarelyContextTheme, locale, current user
Deep subtree, changes oftenContext + a storeRaw context re-renders every consumer
Server dataReact Query / SWRCaching and invalidation, not state
Complex related transitionsuseReducerSeveral fields that change together
Where a value should live, by how far it travels.

Can a component change its own props?

No. Props are read-only within the receiving component, and React freezes the props object in development so an attempted write throws in strict mode. If a component needs to change a value it receives, the value belongs to a parent — pass a callback down and let the owner update it.

Do props and state work the same way in class components?

Conceptually yes. Props arrive as this.props and are read-only; state lives in this.state and is updated with this.setState, which merges the object you pass rather than replacing it. useState replaces instead of merging, which is why you spread the previous value when updating an object.

What are default props?

In function components you use default parameter values — function Button({ variant = "primary" }) — which is now the recommended approach. The old defaultProps static is deprecated for function components in React 19, though it still works on classes.

Why doesn't my child re-render when the parent's state changes?

Usually because the parent mutated an object or array instead of replacing it, so the prop's reference is unchanged and a memoised child skips the render. Occasionally it is a React.memo wrapper with a custom comparison that returns true incorrectly. Replace, do not mutate.

Is state shared between two instances of the same component?

No. Each rendered instance gets its own independent state, keyed by its position in the tree. Two <Counter /> elements count separately. Two instances sharing a value means that value should be lifted to their parent, or moved into context.

Frequently asked questions

What is the difference between props and state in React?
Props are data passed into a component by its parent and are read-only inside that component. State is data the component owns and can update with its setter. Both cause a re-render when they change; the difference is who is allowed to change them.
What are props in React?
Props are the arguments a component receives from whoever renders it, written as attributes in JSX. They can be values, functions, or even other elements — children is a prop React fills from whatever you nest inside the tags. The component reads them and never writes to them.
What is state in React?
State is a value a component keeps between renders and controls itself, created with useState or useReducer. Updating it through the setter tells React to re-render so the screen matches the new value. It is what lets a function component remember anything at all.
Can props change over time?
Yes, frequently. What is fixed is where the change comes from: the parent re-renders with a new value and the child receives it. Within a single render the props are constant, which is what makes a component's output predictable from its inputs.
Can a child component modify props?
No. Props are read-only in the receiving component and React freezes the props object in development. To change a value it receives, the child calls a callback prop and the parent — which owns the value — updates its own state.
What is lifting state up in React?
Moving a piece of state from a component into its closest common ancestor so that two or more components can share it. The ancestor passes the value down as a prop and passes a setter down to whichever child needs to change it. It is React's standard answer to sibling communication.
Should I copy props into state?
Almost never. useState(props.value) reads the prop once at mount and ignores every later change, which is why an edit form keeps showing the previous item's data. Derive the value during render instead, or give the component a key so React remounts it when the identity of the data changes.
Why doesn't my component re-render when I update state?
Usually because you mutated the existing object or array instead of creating a new one. React compares by reference, so items.push(x) followed by setItems(items) looks unchanged. Use [...items, x], items.filter(), or items.map() to produce a new reference.
Do props cause a re-render?
Yes — when a parent re-renders, its children re-render with the new props by default. React.memo can skip that if the props are shallowly equal, which is why passing a freshly created object or inline function as a prop defeats memoisation.
What is prop drilling and how do I avoid it?
Passing a value down through components that do not use it, purely to reach a deeper one. Context removes the intermediate hops for genuinely shared values like theme or the current user. Two or three levels of explicit props are usually clearer than a context, so don't reach for it too early.
Is state private to a component?
Yes. Each rendered instance has its own state, so two of the same component count independently, and nothing outside can read or change it except through what the component chooses to expose. Sharing state means lifting it up or moving it into context.
What is the difference between props and state in class components?
The same distinction: this.props is read-only, this.state is owned by the component. The one behavioural difference is that this.setState merges the object you pass into existing state, while the useState setter replaces it entirely — which is why you spread the previous value when updating an object.

This is 1 of 75+ questions in the React Interview Kit

Get every question with detailed answers, follow-ups and real code — plus coding challenges and a last-minute revision sheet. One-time payment, instant access.

⚡ Get the React Interview Kit → ₹399
Written by Arun Karthikeyan · Last updated

Full kit

React Interview Kit · ₹399

Get it →