Writing Melanie Baratto
Essay 01

Lifting State Up

Two components on the same screen, both displaying a number that was supposed to be the same number, and they disagreed — and neither of them was wrong.

The bug was that the counter said four and the cart said three.

Not intermittently. Reliably, on a Tuesday, in a build that had passed. Two components on the same screen, both displaying a number that was supposed to be the same number, and they disagreed, and neither of them was wrong — each was faithfully showing what it had been given. The counter had been told four. The cart had been told three. Somewhere above them both, at a level neither could see, the truth had forked.

You can spend a whole afternoon on this. You go up the tree one level at a time, and at each level you ask: does this thing know? And mostly it doesn’t. Mostly a component is a small dutiful function that receives what it is handed, arranges it, and passes some portion of it further down. It does not know where the value came from. It does not know what happens to it after. It has no access to the level above it and no memory of having been rendered before.

The fix has a name. It’s in the documentation, on a page you send junior developers, and it is called lifting state up.

The whole refactor
function Cart() {
  const [count, setCount] = useState(0)
  return (
    <>
      <Counter count={count} />
      <Items count={count} onAdd={setCount} />
    </>
  )
}

That’s all it is. The value stops living in two places that can drift and starts living in one place above both of them, and the two children — who own nothing now, who are strictly poorer than they were on Monday — can finally agree, because neither of them is holding anything.

Something worth saying plainly about this work, which sounds mystical only because it’s true: the tree isn’t the interface. A component doesn’t produce buttons and text. It produces a description of buttons and text — an object, a plain one, that says what ought to be on the screen. Something else entirely takes that description and reconciles it against what is actually there, and makes the difference vanish. You never touch the screen. You have never once in your career touched the screen. You write what should be the case, and a process you did not write and cannot see makes the world match.

There is a system for describing how an infinite thing produces a finite one, and its first move is the strange one.

The problem it starts from: if there is something without limit, and it is genuinely without limit, then there is no room anywhere for anything else. Not metaphorically no room. No room. A world cannot be added to a fullness. So before anything can exist, the fullness has to withdraw from a space — contract, step back, leave a vacancy — and only into that vacancy can a bounded thing be put. This is called tzimtzum, and the word means contraction, and the entire architecture of the thing rests on it. Creation begins with a subtraction.

Then, into that cleared space, light. Not all of it — a ray, a narrowed portion, entering a chain of vessels arranged one below the next. Each vessel receives from the one above and transmits to the one below, and each is more bounded, more particular, more able to be handled than the one before. What arrives at the bottom is the same light that started, at a resolution a finite creature can survive. Nothing is added going down. Only limited.

And the vessels break. This is the part the system is honest about. Some of them receive more than their structure can contain and they shatter, and the light they held scatters downward into the ordinary material of the world, into objects, into food, into a chair, into a conversation with someone at a bus stop — sparks, in enormous number, lodged in matter, indistinguishable from the matter.

The work assigned to a person, then, is not to ascend. It is to go through the ordinary world locating what is scattered in it and return it upward, one item at a time, by using the thing correctly. You do not fix the light. The light was never damaged. You fix where it is being held.

Both of these are systems for making an unbounded thing handleable by nesting limits, and both put the fault in the container.

That’s the real overlap, and it isn’t decorative. When my counter and my cart disagreed, nothing was wrong with the number. Four was fine. Four had never been anything but four. What was wrong was that it was being held in two vessels too small to hold it in common, and the repair was not to correct either display but to move the value to where it could be seen from both. Nobody debugs the data. You debug the shape of what’s holding it.

And there’s the second thing, which took me longer to notice: in both systems the work runs upward, and it is undramatic. Lifting state is not a redesign. Nothing new gets built. You find the value sitting in the wrong place, you take it up one level, you delete the copy, and the app is quieter afterward. Nobody demos it. It doesn’t appear in the release notes. It is four lines and an afternoon and it is most of what senior people actually do.

Here is where it stops, and the stopping is the part I keep returning to.

I can see the tree.

I have it open on the left of my screen, the whole thing, root to leaf, and I can collapse a branch or expand it, and when I decide that a value belongs three levels higher I simply put it three levels higher, because I am outside the tree and the tree is a file. The component cannot do this. A component has no idea it is in a tree. It cannot lift its own state up, cannot see the level above it, cannot know that the thing it has been faithfully displaying is a stale copy of something truer held somewhere it has no access to. It just renders four, correctly, forever, until someone outside comes and moves the value.

I am not outside the other one. That is the entire difference and it is not a small one.

So the sparks thing has always struck me as generous, in a way I don’t think people give it credit for. It doesn’t ask you to see the tree. It doesn’t require the diagram. It says: you are inside this, you cannot get a view of it, and the work available to you is local and specific and this-sized — this object, this meal, this Tuesday, this person in front of you — and doing it correctly is sufficient, and you will not get to watch the totals.

I close my laptop at seven. The tree is still on the screen when the screen goes dark, root to leaf, every branch, and I know exactly where everything lives.

For eleven hours a day I get to be the developer. The rest of it I spend as a component.