FRONTEND ARCHITECTURE//5 MIN READ

Killing the 200ms 'Not Found' Flash: TanStack Router Hydration & Job State Machines

How I fixed an asynchronous TanStack Router hydration race condition with a 3-step fallback cascade and built a multi-actor job status state machine in React and Vite.

race conditions love pretending your database is empty.

There is nothing that cheapens a polished web app faster than a UI lie: you tap a valid profile link on mobile, the screen flashes 'Artisan not found' for 200 milliseconds, and then—boom—the profile suddenly appears.

While building our service marketplace frontend with React, Vite, TanStack Router and TanStack Query, hunting down that 200ms flash led straight into how route parameter hydration interacts with asynchronous query hooks.

The Asynchronous 'Artisan Not Found' Hydration Race

When deep-linking to an artisan profile or navigating on mobile, the component mounted while TanStack Router was still hydrating the dynamic route parameters. Because the ID was momentarily undefined on the first tick, the query hook skipped execution or resolved empty, flipping isLoading to false before the router finished supplying the parameter.

  • Built a 3-step ID resolution cascade: check hydrated TanStack route params first → fall back to parsing the URL pathname segment directly → check the warm TanStack Query cache.
  • Guarded the empty/error state boundary so isLoading cannot resolve to false while the route parameter itself is still in flight.
  • Result: Deep links and mobile transitions go straight from skeleton state to the hydrated profile without a single frame of false 'Not Found' UI.

Engineering the Multi-Actor Job Status State Machine

Unlike a standard e-commerce cart where a user clicks 'Buy' and the order is done, a physical service job is a long-running conversation between two people with different permissions. I structured the frontend job view around an explicit state machine:

"Requested → Pending → Accepted → En Route → In Progress → Completed (or Disputed / Cancelled)"

At each node in that chain, the UI dynamically locks or unlocks actions based on both the job status and the viewer's role: multi-step job creation wizards with address autocomplete, counter-offer quotation drawers, escrow payment triggers, and danger-state cancellation dialogs that require structured reason capture.

Micro-UI Polish: The Details Users Feel

Good frontend engineering includes sweating the small visual bugs that erode trust. During our mobile polish pass, I eliminated duplicate service-radius strings that were rendering twice on profile headers, replaced wrapping text blocks with compact atomic badges, and fixed Naira (₦) currency input misalignment by replacing brittle pixel top-offsets with dynamic inset-y-0 flex items-center containers.

my take ↓

Anyway, that's what I've been thinking about lately. Back to building.

From the archive

Read something else.