Lifting State Up
What to do when two sibling components need to share and stay in sync with the same piece of state.
2 min read
State lives inside whichever component calls useState for it, and by default that state is invisible to everything else — including sibling components sitting right next to it in the tree. Problems show up when two components need to agree on the same value.
The problem
Say a temperature input and a conversion display both need the same number, but they're siblings:
function App() {
return (
<div>
<TemperatureInput /> {/* has its own state */}
<ConvertedDisplay /> {/* needs to know the input's value */}
</div>
);
}If TemperatureInput keeps celsius as its own local state, ConvertedDisplay has no way to read it — React components can't reach into a sibling's state directly.
The fix: move state to the common parent
The state moves up to the closest component that contains both of them, and gets passed back down as props:
function App() {
const [celsius, setCelsius] = useState(0);
return (
<div>
<TemperatureInput value={celsius} onChange={setCelsius} />
<ConvertedDisplay celsius={celsius} />
</div>
);
}
function TemperatureInput({ value, onChange }) {
return (
<input
type="number"
value={value}
onChange={(e) => onChange(Number(e.target.value))}
/>
);
}
function ConvertedDisplay({ celsius }) {
return <p>{celsius}°C is {(celsius * 9) / 5 + 32}°F</p>;
}TemperatureInput no longer owns the value — it receives it as a prop and reports changes back up through onChange, which App passed in. This makes TemperatureInput what's called a controlled component: its displayed value is entirely dictated by its parent, not by state it manages itself. Controlled inputs get their own dedicated lesson later in this course.
Finding the right ancestor
The rule from the previous lesson still applies: state should live in the lowest common ancestor that needs it, not higher. Lifting celsius all the way up to some top-level App when only these two components use it means every unrelated component in between has to pass it through as a prop it doesn't otherwise care about — a pattern called prop drilling. For state used by components scattered across distant parts of the tree, the Context API (covered later in this course) is a better fit than lifting state dozens of levels up.
With sharing state between components covered, the next lesson looks at handling the events — clicks, input changes, submissions — that trigger these state updates in the first place.
Test what you just learned
4 quick questions. Get all of them right to unlock the next lesson.
You can take the quiz without an account — logging in just lets your result count toward your progress.