Lifting State Up

Lifting state up means moving state to the closest common ancestor of components that need to share or coordinate that state. The ancestor then passes values down through props and exposes callbacks so children can request state changes.

When two sibling components need the same piece of information, keeping separate copies of that information can cause them to diverge. Instead, place the state in their nearest common parent and make that parent the source of truth.

The parent passes the current state to children through props. A child that needs to change the state receives a callback prop and invokes it with the necessary information; the parent performs the state update and re-renders the affected children.

This pattern is especially useful when one component produces input and another component displays or reacts to it. It keeps ownership of shared state explicit and makes the data flow predictable: state moves downward, while events or update requests move upward.

The state should generally be lifted only as far as necessary. Moving state into a distant ancestor can create unnecessary prop passing and make components harder to maintain; if many unrelated parts of an application need the same state, a dedicated state-management or context-based approach may be more appropriate.

Key points

Interview questions

What does it mean to lift state up in React?

It means moving state from a child component into their nearest common ancestor when multiple components need that state. The ancestor becomes the source of truth. It passes the current value to children through props and passes callbacks when children need to request changes. This avoids having separate, potentially inconsistent copies of the same state.

How would two sibling components share state?

I would move the shared state into their closest common parent. The parent passes the relevant state to each sibling through props and passes update callbacks to whichever sibling needs to modify it. The child invokes the callback rather than directly changing the parent's state. This creates a single source of truth and keeps the data flow explicit.

Why is duplicated state between sibling components problematic?

Two independently managed copies can become inconsistent because an update to one copy does not automatically update the other. That forces developers to add synchronization logic, which increases complexity and creates more opportunities for bugs. A shared owner eliminates the duplicated source of truth. Both siblings then render from the same state value.

How do you decide where state should live?

I start by identifying every component that reads or changes the state and find their closest useful common owner. I keep the state as low in the tree as possible while still making it available to all required consumers. If the state crosses unrelated branches or many layers, I consider Context or a dedicated state-management solution. I also distinguish server data, URL state, and derived values from client UI state because they may have better owners than a component's local state.