Skip to content

Build1 publisher3 min readPublished

startTransition runs your callback immediately and only demotes the set calls inside it

The hook returns a boolean and a function, and the function fires the moment you call it. A dev.to guide tested that against React 19.2.8 and re-ran three checks on 19.3.0, which shipped September 9.

The Engineer · Build desk

What happened

  • A dev.to guide argues that useTransition is the only one of the four React 19 hooks it covers that works on its own, with no form and no other hook driving it.
  • The guide's reading of the contract: startTransition takes one function, runs it right away, and delays or schedules nothing, while set calls made during that run are marked low priority and interruptible.
  • Examples were tested against React 19.2.8, with the race-condition, error-boundary and overlapping-Transition checks re-run on 19.3.0, which shipped on September 9.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Wrapping an expensive computation in a Transition does not move it off the main thread, so a slow pass over a large array blocks for its full duration and only the render it feeds becomes discardable.
  • decision Teams calling startTransition directly own the error path and the captured result themselves; the alternative is moving that handler to useActionState, which returns the value as state.
  • cost Keeping a controlled input responsive costs a second state variable, and the list the user reads is deliberately one keystroke behind the box they are typing in.
  • capability Because isPending stays true until awaited work finishes and its state is shown, one flag can cover a whole async round trip without a separate loading boolean.

Filtering a long list as someone types has no side effect to run and no single result to track, and the dev.to guide says useActionState was never built for it [19]. So the search example uses two pieces of state doing two different jobs. `query` is set outside the Transition. The controlled input updates on the keystroke, and typing never lags [15]. `filterQuery` is set inside it, and the guide says it "lags behind" query on purpose [15]. `filtered` is a plain expression recomputed on every render from `filterQuery`, and not state at all [16].

What the Transition buys is narrower than the wrapper suggests. `products.filter()` still runs as ordinary, uninterrupted JavaScript, exactly as it would outside a Transition [17]. React decides whether the render containing that iteration can be cut in front of by a more urgent update, which here is the next keystroke [17]. The iteration itself is not chunked. One pass over a big array takes as long as it took before; the render it feeds can now be abandoned and restarted [17].

The contract stops at two values, `isPending` then `startTransition`, always in that order [9]. The function returns nothing, so whatever your callback returns is discarded unless you store it yourself [13]. The hook has no built-in error state and no queue [13]. useActionState is the hook that hands back your function's return value as state [14]. A handler that needs the server's answer, or a message on failure, needs code this hook does not supply. The guide calls useTransition "the easiest one to get partially right" [5] and names where that surfaces: a fast double-click, a function that throws, a text input [6].

Nothing about `startTransition` is delayed or scheduled for later, despite the name [11]. The callback runs right away and synchronously, and what changes priority is any `set` call that happens while it is running [11][12]. `isPending` then covers the whole span. It is true at the first `startTransition` call and stays true until every Action in that Transition, including anything you awaited, has completed and the resulting state is shown [10]. In the example that one flag dims the list to 0.6 opacity while stale results are still on screen [18].

Claims about a scheduler need a version attached. The guide tested its examples against React 19.2.8, and re-ran the race condition, error boundary and overlapping-Transition checks on 19.3.0, which shipped on September 9 [7][8]. Those two builds are the only React versions it names [21]. On an earlier 19.x release these are claims about someone else's build, and the guide's later sections, covering the race-condition and error-boundary results, were not available [22].

In my view the two-variable split is the right default anywhere a rendered list derives from an input, because the cost is one extra `useState` and one opacity rule [15][16][18]. I would not reach for it on a submit handler that has a result to report. Three of the four hooks in this series need something else driving [20]. useTransition is the one that drives alone, and it is also the one with the least structure underneath it [1].

What to watch

  • The rest of the guide's double-click and thrown-error sections, and whether the fix it lands on is a guard in the handler or an error boundary.
  • Any React 19.x release that changes when isPending drops, since the documented behaviour is pinned to 19.2.8 and 19.3.0.
  • Whether teams move result-carrying handlers to useActionState once they notice startTransition discards the return value.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories