Lifting State Up in React
Imagine you have two thermometers in different rooms, and you want them to both show the same temperature. When you adjust one, the other should update automatically. How do you make them share the same temperature value? This is where **lifting state up** comes in.
What is Lifting State Up?
In React, data flows down from parent to child via props. But sometimes, multiple components need to share and synchronize the same data. The solution is to move ("lift") the shared state up to their closest common ancestor. This ancestor component holds the state and passes it down to the children via props, along with functions to update that state.
Lifting state up is a pattern where you move shared state to the closest common ancestor of components that need it.
The Problem: Isolated State
Let's say we have two temperature inputs that should stay in sync:
<!-- Child component with its own state -->function TemperatureInput({ scale }) { const [temperature, setTemperature] = useState('');
return ( <fieldset> <legend>Enter temperature in {scale}:</legend> <input value={temperature} onChange={(e) => setTemperature(e.target.value)} /> </fieldset> );}
<!-- Parent component using two independent temperature inputs -->function Calculator() { return ( <div> <TemperatureInput scale="Celsius" /> <TemperatureInput scale="Fahrenheit" /> </div> );}Each `TemperatureInput` has its own state. Changing one doesn't affect the other. They are completely independent, which is not what we want.
The Solution: Lift State Up
We move the state to the parent `Calculator` component and pass it down to both inputs via props, along with a function to update it.
<!-- Child component now receives props -->function TemperatureInput({ scale, temperature, onTemperatureChange }) { return ( <fieldset> <legend>Enter temperature in {scale}:</legend> <input value={temperature} onChange={(e) => onTemperatureChange(e.target.value)} /> </fieldset> );}
<!-- Parent holds the shared state -->function Calculator() { const [temperature, setTemperature] = useState(''); const [scale, setScale] = useState('c');
<!-- Conversion functions --> function handleCelsiusChange(value) { setTemperature(value); setScale('c'); }
function handleFahrenheitChange(value) { setTemperature(value); setScale('f'); }
<!-- Calculate values for display --> const celsius = scale === 'f' ? convertToCelsius(temperature) : temperature; const fahrenheit = scale === 'c' ? convertToFahrenheit(temperature) : temperature;
return ( <div> <TemperatureInput scale="Celsius" temperature={celsius} onTemperatureChange={handleCelsiusChange} /> <TemperatureInput scale="Fahrenheit" temperature={fahrenheit} onTemperatureChange={handleFahrenheitChange} /> </div> );}How It Works
- The `Calculator` component holds the shared state (`temperature` and `scale`).
- It passes the current temperature and a function to update it to each `TemperatureInput` via props.
- When the user types in either input, it calls the appropriate `onTemperatureChange` function passed from the parent.
- The parent updates its state, which causes both child components to re-render with the new values.
Benefits of Lifting State Up
- Single Source of Truth: The shared state exists in only one place (the parent), eliminating inconsistencies.
- Synchronization: All children that need the same data stay in sync automatically.
- Predictable Data Flow: Data still flows down (via props), and changes flow up (via callbacks).
- Easier Debugging: Since state is centralized, it's easier to track where and when state changes.
When to Lift State Up
- When two or more components need to share the same changing data.
- When a component needs to control or coordinate the state of its children.
- When you find yourself passing data through multiple layers just to reach a sibling (this is a sign to lift state up).
Two Minute Drill
- Lifting state up means moving shared state to the closest common ancestor of components that need it.
- The parent holds the state and passes it down to children via props, along with functions to update it.
- This ensures a single source of truth and keeps all components in sync.
- Data still flows down (props), changes flow up (callbacks).
- Use this pattern whenever multiple components need access to the same changing data.
Need more clarification?
Drop us an email at career@quipoinfotech.com
