Sometimes, two or more components need to share or synchronize data. Instead of duplicating state in each component, React encourages a technique called “Lifting State Up.”
It means moving shared state to the closest common ancestor component, so all child components can use the same data via props. This keeps your UI consistent and easier to reason about.
? Goal: Single source of truth in a parent component
props.Here, each input component manages its own temperature. They are related, but their states are completely independent, so typing in one box does not affect the other.
// Each input manages its own local temperature state
function CelsiusInput() {
const [temp, setTemp] = React.useState("");
return (
<input
value={temp}
onChange={(e) => setTemp(e.target.value)}
placeholder="Celsius"
/>
);
}
function FahrenheitInput() {
const [temp, setTemp] = React.useState("");
return (
<input
value={temp}
onChange={(e) => setTemp(e.target.value)}
placeholder="Fahrenheit"
/>
);
}
CelsiusInput and FahrenheitInput both store their own temp value. There is no connection between them, so updating one component does nothing to the other. This can cause inconsistent data when the values should actually be synchronized.
Now we move the temperature state into a parent component. The parent becomes the single source of truth, and children receive values and setter callbacks via props.
// Parent owns the temperature; children just display and update it
function TemperatureCalculator() {
const [celsius, setCelsius] = React.useState("");
const toFahrenheit = (c) => (c * 9) / 5 + 32;
return (
<div>
<CelsiusInput value={celsius} onChange={setCelsius} />
<FahrenheitDisplay fahrenheit={toFahrenheit(celsius)} />
</div>
);
}
function CelsiusInput({ value, onChange }) {
return (
<input
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="Celsius"
/>
);
}
function FahrenheitDisplay({ fahrenheit }) {
return <p>Fahrenheit: {fahrenheit}</p>;
}
TemperatureCalculator holds the celsius state.CelsiusInput receives the value and the setCelsius updater via props.FahrenheitDisplay always shows the latest converted value from that parent state.Because both children depend on the same parent state, the UI stays in sync and easier to maintain.
Two sibling components (Sender and Receiver) share data by lifting state into their common parent. They never talk directly to each other — only through the parent.
// Parent holds the shared message, siblings read/write through props
function Parent() {
const [message, setMessage] = React.useState("");
return (
<div>
<Sender onSend={setMessage} />
<Receiver message={message} />
</div>
);
}
function Sender({ onSend }) {
return (
<input
placeholder="Type message"
onChange={(e) => onSend(e.target.value)}
/>
);
}
function Receiver({ message }) {
return <p>Received: {message}</p>;
}
Sender updates the parent’s message state using onSend. Receiver reads that same state via the message prop. Any change in Sender instantly appears in Receiver.
useEffect and callbacks when you need side effects tied to shared state.100°C.Goal: Practice lifting shared state to a parent component so that related or sibling components always stay in sync and follow React’s one-way data flow.