Matt Brophy
banner
brophdawg11.com
Matt Brophy
@brophdawg11.com
Helping folks build better websites
Remix/React Router @Shopify 💿
Philadelphia
ok - good to know. From the beginning it has sounded like it was a popstate/transition issue.

When the bug is fixed, will `startTransition(() => navigate(delta))` behave the same as `startTransition(() => navigate(path))` for RR apps?

If so we can just remove the entire popstate section.
November 25, 2025 at 6:45 PM
ok - we've had reports of uSES/startTransition bugs in v7 that sounds like tearing, but in large apps and no minimal repro yet so we may have jumped to the wrong conclusion there
November 25, 2025 at 6:28 PM
Is it accurate to say popstate navigations do not work with async transitions?
November 25, 2025 at 3:43 PM
FWIW Brooks made some cleanups in github.com/remix-run/re... because the historical aspect felt more blog-posty and less documentation in case that was part of what you took issue with
November 25, 2025 at 3:40 PM
No shade intended, anything more specific?

I would argue in response that React might be oversimplifying transitions - they're not without complexity.

The design decisions were made *before* transitions, we're trying our best to update without major/breaking changes.
November 25, 2025 at 3:36 PM
It took long enough for things to stabilize but thank god they finally started to
November 23, 2025 at 12:25 AM
Y’all have people interested in your PRs?
a man in a black jacket and white pants is standing in the dirt .
Alt: George Michael Bluth sad walking
media.tenor.com
November 19, 2025 at 10:29 PM
yeah - check out the thread - that's by design in React it seems like
November 19, 2025 at 3:45 PM
yeah we're not fully compatible today - that's what I've been working on this past week. New flag to wrap RR Link navigations in startTransition and leverage useOptimistic internally to surface useNavigation updates

When I get a WG post together I can include a demo using an experimental build
November 18, 2025 at 8:03 PM
Missed this one before - for a new routing lib in 2025 that makes total sense.

But we're using patterns developed pre-react 18/transitions/use() and trying to avoid breaking changes/major architectural changes for a huge user base. We were hoping startTransition(promise) gave us that avenue.
November 18, 2025 at 7:44 PM
The react 18 concurrent announcement post even states "router libraries will automatically wrap navigations in startTransition"

We're just trying to get up to date there really and be "concurrent friendly"
November 18, 2025 at 7:14 PM
Docs only say an action is "A function that updates some state by calling one or more set functions" - which is what navigate does.

The word "mutation" isn't in the useTransitions page?
November 18, 2025 at 7:13 PM
In our case the transition would be started before the popstate though right? I would like for

startTransition(()=>navigate(path))
startTransition(()=>navigate(delta))

To work the same and avoid having to explain/document the nuance in behavior.

Feels like users would expect them to be the same
November 18, 2025 at 7:04 PM
yeah I threw the effect in there to confirm since I couldn't always see the renders
November 18, 2025 at 6:03 PM
I think I was misremembering the batching since it's across an await but would still be a new microtask. We may need to conditionally await only if any loaders returned a promise to allow totally sync loaders. And tell users not to use async functions if they want that behavior
November 18, 2025 at 6:03 PM
Loaders have been async Remix v1 (since they were HTTP calls)

I thought I had confirmed React batching meant that sync loaders never actually surfaced a "loading" state to the UI but I'm not seeing that at the moment - maybe we let an async tick slip in somewhere

stackblitz.com/edit/github-...
November 18, 2025 at 5:44 PM
ok cool - I'll try to summarize a bit and get something added in there 👍
November 18, 2025 at 5:24 PM
We're a router, not a cache?

Users choose:
- cache in the client - sync loaders
- cache in a CDN - async loaders
- don't cache - async loaders

But holding onto every bit of loaderData that has loaded in a given session in the router sounds like a cache expiration nightmare.
November 18, 2025 at 5:20 PM
also, happy to move this to discord or somewhere if that's easier
November 18, 2025 at 4:45 PM
With popstate, we don't know the path until _after_ it has fired and we can read window.location, so we can't match routes beforehand and make a state update.

I should have included that the "loading" state also includes the location we're loading - which is the part we don't know up front
November 18, 2025 at 4:45 PM
Thats where loaders would execute. Overly simplified, a navigation in React Router is multiple sync/async steps:

navigate(path)
- match routes
- setState({ state: 'loading' })
- call loaders (async)
- setState({ state: 'idle', loaderData, matches })
November 18, 2025 at 4:43 PM