Lifting State Up in React: A Step-by-Step Example

Lifting state up moves shared state to a common parent. Follow a step-by-step example to share one value between two React components.

5 min read

In React, lifting state up means moving shared state to the closest common parent of the components that need it. The parent keeps the value, passes it down as props, and passes a handler down so children can update it. This gives the app one source of truth for that value.

The problem: two independent counters

Start with a Counter that keeps its own number and updates on click. This is the uncontrolled version, and it shows why sharing becomes hard:

App.jsxApp.jsx
import { useState } from "react";
 
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount((previous) => previous + 1)}>{count}</button>
  );
}

Render two counters in App and each one updates on its own, because each owns a separate count. Now imagine the goal is one total shared by both buttons. The value can no longer live inside either Counter, so it must move up.

Step 1: remove state from the child

Turn the child into a display-only component. It reads the count and a click handler from props instead of owning them:

App.jsxApp.jsx
function Counter({ count, onIncrement }) {
  return <button onClick={onIncrement}>{count}</button>;
}

The Counter no longer decides what happens on click. It renders the value it receives and triggers the handler the parent gives it.

Step 2: move state to the shared parent

The parent now owns the count and passes it to both children:

App.jsxApp.jsx
function App() {
  const [count, setCount] = useState(0);
  const increment = () => setCount((previous) => previous + 1);
  return (
    <>
      <Counter count={count} onIncrement={increment} />
      <Counter count={count} onIncrement={increment} />
    </>
  );
}

Both counters show the same number. Clicking either one increments the single count in App, and both update together because they read the same prop.

Step 3: pass a handler for changes

The handler is the second half of lifting state. A child cannot call setCount directly, because that function belongs to App. Passing increment as a prop is what lets the child ask the parent to change state.

The full pattern is: state moves up, and both the value and an updater come back down. The parent becomes the single source of truth, and the children stay controlled by props.

When to lift state

Lift state when two or more components must stay in sync. If a value is used by only one component, leave it local.

  • Same value shown in two places: lift it.
  • One component changes and another must react: lift it.
  • A value only one component uses: keep it local.

You will move state up and back down often while a component tree grows. That is a normal part of designing React apps.

Keep the lifted state as low as possible. State that sits too high makes more components re-render than necessary, so place it in the closest parent that all readers share.

What to learn next

See the full set of options in the guide to sharing data, then build controlled child components that follow this pattern.

Rune AI

Rune AI

Key Insights

  • Lift shared state to the closest common parent.
  • Remove the state from the child components first.
  • Pass the value down as a prop.
  • Pass a handler down so children can update it.
  • Keep values that only one component uses local.
RunePowered by Rune AI

Frequently Asked Questions

What does lifting state up mean?

It means moving shared state out of child components into their closest common parent. The parent owns the value and passes it down as props along with a handler to update it.

Why lift state up instead of duplicating it?

Duplicated state can fall out of sync. Lifting it gives the app a single source of truth, so every component reads the same value and updates together.

Where should lifted state live?

In the closest common parent of the components that need it. Keep it as low as possible so unrelated parts of the tree do not re-render with it.

Conclusion

Lifting state up is a three step move: remove state from the child, add it to the shared parent, and pass the value and a handler back down. It gives each piece of shared data one source of truth.