Topic 20 of 54
Lifting State Up
Overview
In React, state flows downwards via props. But what if two sibling components need to share and modify the same data? For example, an `Accordion` where opening one panel closes the others, or a `SearchBar` that filters a `ProductList`. Because siblings cannot communicate directly, you must 'Lift the State Up' to their closest common parent component.
Syntax
By moving the state to the parent, both children can read it. By passing the setter function (`setShippingMethod`) to the child as a prop, the child can trigger updates in the parent.
The Pattern
jsx
// The Parent holds the state and the setter function
function CheckoutPage() {
// State lifted up here!
const [shippingMethod, setShippingMethod] = useState("standard");
return (
<div>
{/* Pass the state AND the setter down as props */}
<ShippingSelector
selected={shippingMethod}
onChange={setShippingMethod}
/>
{/* Sibling can now react to the same state */}
<OrderSummary
method={shippingMethod}
/>
</div>
);
}The child acts as a 'Controlled Component'. It doesn't manage its own state; it relies entirely on the parent to tell it what is selected.
The Child Component
jsx
// The child receives the state and setter via props
function ShippingSelector({ selected, onChange }) {
return (
<select
value={selected}
onChange={(e) => onChange(e.target.value)}
>
<option value="standard">Standard (5 Days)</option>
<option value="express">Express (Next Day)</option>
</select>
);
}Common Pitfalls
- Lifting state too high. If you lift every single piece of state to the root `App` component, your entire application will re-render on every keystroke. Only lift it to the *closest* common ancestor.
Interview Tips
- 'Lifting State Up' is a fundamental React design pattern. Be prepared to explain it in architectural interviews when asked how to share data between completely separate UI widgets.
Real-World Example
A Global Search bar in a Header filtering a List in the Main Content area.
example
jsx
function AppLayout() {
const [searchQuery, setSearchQuery] = useState("");
return (
<div>
<header>
{/* Header can update the query */}
<SearchInput value={searchQuery} onSearch={setSearchQuery} />
</header>
<main>
{/* Main can read the query to filter data */}
<ProductGrid filter={searchQuery} />
</main>
</div>
);
}