Lifting state up — sharing data
When two components need the same data
Imagine two components: a temperature Input and a Display showing it. They both need the same value. Where should the state live? Not in either child alone — because the other could not see it. The answer: move the state up to their nearest common parent. This is called lifting state up.
The pattern
The parent holds the state and passes two things down:
- the value (as a prop), and
- a function to change it (also as a prop).
function Parent() {
const [text, setText] = useState("");
return (
<div>
<Input value={text} onChange={setText} />
<Display text={text} />
</div>
);
}
function Input({ value, onChange }) {
return (
<input value={value} onChange={(e) => onChange(e.target.value)} />
);
}
function Display({ text }) {
return <p>You typed: {text}</p>;
}
How does the child "talk back" to the parent?
This is the key idea. Data flows down as props (value), but a child changes parent state by calling a function the parent gave it (onChange).
So the flow is:
- The user types in
Input. InputcallsonChange(newValue)— which is really the parent'ssetText.- Parent state updates → both
InputandDisplayre-render with the new value.
The parent owns the data; children receive it and request changes through callbacks.
Why does this matter?
Because it keeps a single source of truth. When shared data lives in one place (the parent), every child stays in sync automatically — no copies getting out of step. This pattern is the backbone of almost every React app.
Lift shared state up to the common parent. Pass the value down as a prop, and a setter function down as a prop. Children request changes by calling that function. One source of truth, always in sync.