State & InteractionIntermediate6 min09 / 12

Lifting State Up

When two components need the same data, move that state to their closest common parent and pass it down as props.

Sometimes two sibling components need to share the same piece of data — a filter and a list, or two inputs that should stay in sync. Since data flows down in React (parent → child via props), the fix is to lift the state up to their closest common parent.

#The pattern

  1. Move the useState into the common parent.
  2. Pass the value down to children as props.
  3. Pass a setter (or a callback) down so children can request changes.

The parent owns the state; children become simpler, controlled by their props.

parent owns the state, children share it
function App() {
  const [query, setQuery] = useState('');
  return (
    <>
      <SearchBox query={query} onChange={setQuery} />
      <Results query={query} />
    </>
  );
}

function SearchBox({ query, onChange }) {
  return <input value={query} onChange={e => onChange(e.target.value)} />;
}

function Results({ query }) {
  return <p>Searching for: {query || '…'}</p>;
}

SearchBox and Results don't hold the state — App does. When you type, SearchBox calls onChange, App updates query, and both children re-render with the new value. One source of truth, always in sync.

Tip

How high should it go?

Lift state only as high as the closest common ancestor of the components that need it — no higher. Lifting too far makes unrelated components re-render and adds prop-drilling. When many distant components need it, reach for Context instead.

Quick check

Two sibling components need to share a value. Where should that state live?

Key takeaways

  • Data flows down via props, so shared state belongs in a common parent.
  • Pass the value down as a prop and a setter/callback down to request changes.
  • Lift only to the closest common ancestor — not higher.
  • For state needed by many distant components, use Context instead of deep prop-drilling.
Practice challenges
Test yourself · earn XP
0/3
Predict the output#1

Two siblings must share a counter. Following 'lifting state up', where should the useState live?

predict-output
// <App>
//   <Display />   needs to READ count
//   <Controls />  needs to CHANGE count
Fix the bug#2

The child can't change the parent's state. What should the parent pass down?

fix-bug
function App() {
  const [on, setOn] = useState(false);
  return <Toggle value={on} />; // child needs to flip it
}
Reorder the lines#3

Order the steps to lift state up so two siblings can share it.

1
Pass a setter or callback down so a child can request a change
2
Move the useState into the closest common parent
3
A child calls the callback, the parent updates state, both children re-render
4
Pass the value down to each child as a prop
Your turn
Practice exercise

Two <TemperatureInput> components (Celsius and Fahrenheit) should stay in sync. Where does the shared temperature state belong, and what do the inputs receive?

Try it live — edit the code and hit Run to see it rendered:

solution.jsx · editable