Lifting State Up in React Explained for Beginners
Lifting state up in React explained for beginners: learn how to share state between components with simple examples, clear steps and common mistakes to avoid.
Lifting state up in React explained for beginners: learn how to share state between components with simple examples, clear steps and common mistakes to avoid.
Lifting state up in React means moving a piece of state from a child component to its closest shared parent, so that two or more components can use the same data. If you have ever asked "how do I share state between components in React?", this is the answer. In this guide you will learn what it means, why it is needed, and how to do it step by step with small examples.
You do not need to be an expert. If you know what a component, props and state are, you are ready. If not, a quick read of our guide on props vs state will help first.
In React, data flows in one direction: from parent to child, using props. A child can read the props it receives, but it cannot hand data to its sibling directly. A sibling is another component that has the same parent.
Imagine a page with a text box and a preview below it. The preview must show whatever you type. If each component keeps its own state, they cannot see each other's data. Here is what that broken version looks like.
import { useState } from 'react';
function Input() {
const [text, setText] = useState('');
return <input value={text} onChange={(e) => setText(e.target.value)} />;
}
function Preview() {
const [text, setText] = useState('');
return <p>You typed: {text}</p>;
}Both components have their own text state. Typing in Input changes only the Input copy. The Preview copy stays empty forever. They are two separate boxes that never talk to each other.
The fix has three steps. First, find the closest parent that contains both components. Second, move the state into that parent. Third, pass the value and a function to change it down to the children as props.
Let us fix the broken example. We create a parent called App that owns the state.
import { useState } from 'react';
function App() {
const [text, setText] = useState('');
return (
<div>
<Input text={text} onTextChange={setText} />
<Preview text={text} />
</div>
);
}Line 4 creates the state in App, not in the children. In the Input line, we pass two props: the current value (text) and the setter function (onTextChange). In the Preview line, we pass only the value, because Preview just displays it.
function Input({ text, onTextChange }) {
return (
<input
value={text}
onChange={(e) => onTextChange(e.target.value)}
/>
);
}
function Preview({ text }) {
return <p>You typed: {text}</p>;
}Input no longer has its own state. It shows the value it receives and, when you type, it calls onTextChange with the new text. That call runs setText inside App. React then re-renders App, and both children receive the new value. Now the preview updates as you type.
A source of truth is the one place where a piece of data really lives. After lifting state up, the text lives only in App. Everything else is a view of it. This avoids bugs where two copies of the same data disagree.
Data goes down through props. Changes go up through functions. Developers often say: data flows down, events flow up.
Here is another common case. Two buttons each count clicks, and the parent shows the total.
function App() {
const [likes, setLikes] = useState(0);
const [loves, setLoves] = useState(0);
return (
<div>
<CountButton label="Like" count={likes} onClick={() => setLikes(likes + 1)} />
<CountButton label="Love" count={loves} onClick={() => setLoves(loves + 1)} />
<p>Total: {likes + loves}</p>
</div>
);
}
function CountButton({ label, count, onClick }) {
return <button onClick={onClick}>{label}: {count}</button>;
}The parent holds both numbers, so it can add them up for the total. CountButton is now a simple reusable component with no state of its own. It receives a label, a count and a click handler. Components like this are easy to test and reuse.
| Situation | What to do |
|---|---|
| Only one component uses the data | Keep the state inside that component |
| Two sibling components need the same data | Lift state to their parent |
| A parent also needs to read the data | Lift state to the parent |
| Many distant components need the data | Lift higher, or later learn Context |
A good rule: keep state as low as possible, and lift it only as far as needed. Lifting too high makes the parent messy.
It means moving state from a child component into a shared parent component. The parent then passes the data down as props. This lets several components use and update the same data.
Put the state in their closest common parent with useState. Pass the value to both children as props, and pass the setter function to any child that needs to change it.
Not directly. The parent passes down a function, usually the setter or a handler built from it. The child calls that function, and the parent updates its own state.
No. Lifting state up uses props and works well for nearby components. Context is a tool for sharing data with many deeply nested components without passing props through every level.
Only to the closest parent that contains every component needing the data. Keeping state low makes your code simpler and easier to follow.
New to props and state? Read our beginner guide to understand the difference first.
Read props vs stateWant help building a React app for your business? Talk to the Fepiq team.
Contact FepiqOccasional, no-fluff notes on shipping modern software — startups, automation, Laravel, Shopify and more. No spam, unsubscribe anytime.
Keep reading
Learn SQL CASE WHEN step by step. This beginner guide shows how to label, group and sort data with simple examples you can copy and run today.
PostgreSQL ILIKE explained for beginners: search text without worrying about case, learn % and _ wildcards, and copy simple examples you can run today.
Let's build something
Book a free discovery call. We'll listen, ask sharp questions, and send you a proposal within 3 business days.