Lifting State Up

When Two Siblings Need the Same Value, Their Parent Owns It

Lifting State Up

Move state to the lowest common parent of the components that need it. Pass the value down via props and a setter back up via a callback.

4 min read Level 2/5 #react#state#lifting
What you'll learn
  • Recognize when state belongs in a parent
  • Pass state down, send updates up

When two sibling components both need to read or write the same value, neither one can own that state alone. The fix: move the state up to their common parent.

The Problem

Imagine two components that should stay in sync:

function Page() {
  return (
    <>
      <Slider />     {/* sets a value */}
      <Readout />    {/* shows the same value */}
    </>
  );
}

If Slider owns the state, Readout can’t see it. If Readout owns it, Slider can’t change it. Either way, it’s stuck.

The Fix — Lift It Up

Move the state to the parent. Pass the value down to one child via a prop, and pass a setter down to the other:

function Page() {
  const [value, setValue] = useState(0);
  return (
    <>
      <Slider value={value} onChange={setValue} />
      <Readout value={value} />
    </>
  );
}

function Slider({ value, onChange }) {
  return (
    <input
      type="range"
      value={value}
      onChange={e => onChange(Number(e.target.value))}
    />
  );
}

function Readout({ value }) {
  return <p>Value is {value}</p>;
}

Now both children see the same value, and either one can update it through the setter passed in.

The Pattern

DirectionWhat flows
Down (props)The current value
Up (callbacks)“User just did something — here’s the new value”

This is sometimes called one-way data flow, and it’s how React encourages you to think about UIs.

How High Do You Lift?

The lowest common parent. Don’t put state at the top of the app just because. If only one branch of the tree cares, that’s where the state belongs.

When Lifting Gets Painful

If you find yourself threading the same state down through 5 layers of components, each just passing it through, you have prop drilling. The fix is useContext (covered in chapter 5).

Up Next

A specific kind of lifted state: a form input’s value lives in React, not in the DOM. That’s a controlled input.

Controlled Inputs →