DevPath · Learn to code ESPTEN

useReducer and Context

Lifting state up

Sharing state between siblings

Sometimes two sibling components need to share the same data: for example, two fields that must stay synchronized, or a list and a total that depends on it. Where does that state live?

The technique is called "lifting state up": you place the state in the nearest common ancestor and pass down to the children whatever they need.

function Parent() {
  const [text, setText] = useState("");

  return (
    <div>
      <Input value={text} onChange={setText} />
      <Echo text={text} />
    </div>
  );
}

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

function Echo({ text }) {
  return <p>You typed: {text}</p>;
}

The two key ideas:

This way the parent is the single source of truth, and all the children that depend on the data stay consistent. When the tree grows and passing callbacks through many levels becomes awkward, that's the signal to combine it with Context (and even with useReducer) to centralize both the state and its logic.

Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
← Context API: avoiding prop drillingView the module →