Lifting State Up
Finding the right owner for a piece of state when two components need it.
What you'll learn
- Why two components cannot share their own state
- Moving state to the closest common parent
- Passing a value down and a callback up
- How far to lift, and when not to
The problem
State inside a component belongs to that component. Two siblings each calling
useState get two separate values, and neither can see the other's.
Below, each panel keeps its own count. They will not agree, no matter what you click:
That independence is often exactly what you want. But when the two must show the
same number, no amount of work inside Panel will do it.
Lift it to the common parent
The fix has a shape you will use constantly:
- Move the state up to the closest component that contains both.
- Pass the value down as a prop.
- Pass a function down so the child can ask for a change.
The child stops owning the value and becomes controlled by its parent:
Data still flows one way. The child never reaches up — it calls a function the parent gave it, and the parent decides what that means. This is the pattern from Components and Props, now doing real work.
A worked example
Two inputs showing the same value in different units. Neither can own the temperature, because editing either must update both:
Note what is not state: fahrenheit is calculated during render from
celsius. Storing both would let them disagree. Keep one source of truth and
derive the rest — the same point as "you might not need an effect" in
useEffect.
How far to lift
Lift to the closest common parent, and no further. Every level above that gets a prop it does not care about, and every state change re-renders a larger part of the tree.
When the distance is genuinely large — a theme, the signed-in user — the answer
is not to lift through ten layers but
useContext. When the transitions get complicated,
useReducer in the parent keeps them in one place.
Common mistakes
- Duplicating state in the child. Copying a prop into
useStategives the child a stale copy that stops following the parent. - Lifting too far. State at the root that only two leaves use.
- Storing what you can derive. Two values that must agree will eventually disagree.
Exercise
The search box filters nothing, because SearchInput keeps the query to itself
while Results cannot see it. Lift the query into App so typing filters the
list.