Lifting State Up

0/3 in this phase0/36 across the roadmap

📖 Concept

In React, data flows down. But what if two sibling components need to share the same data? You "lift" that state up to their closest common ancestor.

The Pattern:

  1. Move the state from the children to the parent.
  2. Pass the state down as props to the children.
  3. Pass "callback functions" (setters) down as props so children can request state changes.

Why do this?

  • Single Source of Truth: Ensures all components are in sync.
  • Predictability: You know exactly where the data lives and how it's changed.
  • Consistency: Avoids "split" state where two components think the value is different.

💻 Code Example

codeTap to expand ⛶
1import React, { useState } from 'react';
2
3// 1. Child component that accepts data and a callback
4const TemperatureInput = ({ scale, temperature, onTemperatureChange }) => {
5 return (
6 <fieldset className="border p-4 rounded">
7 <legend className="font-semibold px-2">Enter temperature in {scale}:</legend>
8 <input
9 className="border p-2 w-full mt-2"
10 value={temperature}
11 onChange={(e) => onTemperatureChange(e.target.value)}
12 />
13 </fieldset>
14 );
15};
16
17// 2. Parent component that "owns" the state
18function Calculator() {
19 const [temp, setTemp] = useState('');
20 const [scale, setScale] = useState('c');
21
22 const handleCelsiusChange = (value) => {
23 setTemp(value);
24 setScale('c');
25 };
26
27 const handleFahrenheitChange = (value) => {
28 setTemp(value);
29 setScale('f');
30 };
31
32 const celsius = scale === 'f' ? (temp - 32) * 5 / 9 : temp;
33 const fahrenheit = scale === 'c' ? (temp * 9 / 5) + 32 : temp;
34
35 return (
36 <div className="p-10 max-w-xl mx-auto space-y-4">
37 <h2 className="text-2xl font-bold">Temperature Converter</h2>
38
39 <div className="grid grid-cols-2 gap-4">
40 <TemperatureInput
41 scale="Celsius"
42 temperature={celsius}
43 onTemperatureChange={handleCelsiusChange}
44 />
45 <TemperatureInput
46 scale="Fahrenheit"
47 temperature={fahrenheit}
48 onTemperatureChange={handleFahrenheitChange}
49 />
50 </div>
51
52 <div className="mt-4 p-4 bg-yellow-50 rounded border border-yellow-200">
53 {celsius >= 100 ? (
54 <p className="text-orange-600 font-bold">The water would boil! 🔥</p>
55 ) : (
56 <p className="text-blue-600">The water would not boil. 💧</p>
57 )}
58 </div>
59 </div>
60 );
61}
62
63export default Calculator;

🏋️ Practice Exercise

  1. Create a 'Login' form where the 'Email' and 'Password' components are separate, but the 'Submit' button in the parent knows both values.
  2. Build a search interface where one component has the 'Search Input' and another displays the 'Filtered List'.
  3. Implement a 'Multi-step Form' where state is lifted to the parent to keep track of progress across steps.
  4. Experiment with lifting state "too high" and notice how it causes unnecessary re-renders in unrelated components.

⚠️ Common Mistakes

  • Lifting state too high (lifting it to App when only two small components need it).

  • Duplicating state (keeping a copy in the parent AND the child).

  • Passing too many props instead of grouping them into an object.

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for Lifting State Up