In React, lifting state up means moving shared state to the closest common parent of the components that need it. The parent keeps the value, passes it down as props, and passes a handler down so children can update it. This gives the app one source of truth for that value.
The problem: two independent counters
Start with a Counter that keeps its own number and updates on click. This is the uncontrolled version, and it shows why sharing becomes hard:
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount((previous) => previous + 1)}>{count}</button>
);
}Render two counters in App and each one updates on its own, because each owns a separate count. Now imagine the goal is one total shared by both buttons. The value can no longer live inside either Counter, so it must move up.
Step 1: remove state from the child
Turn the child into a display-only component. It reads the count and a click handler from props instead of owning them:
function Counter({ count, onIncrement }) {
return <button onClick={onIncrement}>{count}</button>;
}The Counter no longer decides what happens on click. It renders the value it receives and triggers the handler the parent gives it.
Step 2: move state to the shared parent
The parent now owns the count and passes it to both children:
function App() {
const [count, setCount] = useState(0);
const increment = () => setCount((previous) => previous + 1);
return (
<>
<Counter count={count} onIncrement={increment} />
<Counter count={count} onIncrement={increment} />
</>
);
}Both counters show the same number. Clicking either one increments the single count in App, and both update together because they read the same prop.
Step 3: pass a handler for changes
The handler is the second half of lifting state. A child cannot call setCount directly, because that function belongs to App. Passing increment as a prop is what lets the child ask the parent to change state.
The full pattern is: state moves up, and both the value and an updater come back down. The parent becomes the single source of truth, and the children stay controlled by props.
When to lift state
Lift state when two or more components must stay in sync. If a value is used by only one component, leave it local.
- Same value shown in two places: lift it.
- One component changes and another must react: lift it.
- A value only one component uses: keep it local.
You will move state up and back down often while a component tree grows. That is a normal part of designing React apps.
Keep the lifted state as low as possible. State that sits too high makes more components re-render than necessary, so place it in the closest parent that all readers share.
What to learn next
See the full set of options in the guide to sharing data, then build controlled child components that follow this pattern.
Rune AI
Key Insights
- Lift shared state to the closest common parent.
- Remove the state from the child components first.
- Pass the value down as a prop.
- Pass a handler down so children can update it.
- Keep values that only one component uses local.
Frequently Asked Questions
What does lifting state up mean?
Why lift state up instead of duplicating it?
Where should lifted state live?
Conclusion
Lifting state up is a three step move: remove state from the child, add it to the shared parent, and pass the value and a handler back down. It gives each piece of shared data one source of truth.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.