Optimistically change URL and state without waiting for async to resolve
I have a list of <A/> in the sidebar.
The pages that those <A/> link to have an async data using createAsync. The whole page component is wrapped in a Suspense boundary with a spinner fallback.
Current behavior: when clicking a link, the URL and the state (in this case, the activeClass prop in the <A/>) stays the same until the whole request or the async data is resolved. While navigating, the page component displays the fallback spinner as it should, not the URL and and the <A/> state doesn't update.
Ideal situation: URL changes and and page state is updated instantaneously without waiting for the request to resolve.
Is there a way that the URL and state are automatically changed while navigating?
3 Replies
Just shining a different perspective on this:
https://x.com/jaffathecake/status/1529031579980419072
A browser doesn't show the URL in the address bar until it has updated the DOM (which is a blank page for client side rendered apps which eventually show a spinner when the JS starts running).
The router not updating link states until the content promise has resolved is entirely consistent with the way browsers (i.e. the web) work. What you call “optimistic update” could be judged by others as screen tearing.
I'm just trying to offer an explanation for a default that doesn't meet your expectations.
Are you utilizing preload to minimize the loading time? If it's fast, it might not need to be optimistic.
Jake Archibald (@jaffathecake) on X
Playing around with a few framework routers… it seems like it's common to:
1. Update the URL
2. Fetch stuff for the new view
3. Update the DOM
This leaves a period where the old content is displayed under the new URL. That seems like bad UX, and fragile.
Twitter
Progress Bars Are Best for Process-Related Indicators.
A typical way to deal with this, is to implement paint holding with
useTransition
while giving feedback with a global loading indicator.
That way the old content remains until the entire page, router and all is ready to update.Nielsen Norman Group
Skeleton Screens 101
A skeleton screen is used as a placeholder while users wait for a page to load. This progress indicator is used for full page loads and reduces the perception of a long loading time by providing clues for how the page will ultimately look.
Chrome for Developers
Paint Holding - reducing the flash of white on same-origin navigati...
A quick overview of paint holding. A Chrome feature for reducing the flash of white on same-origin navigations
peerreynders
StackBlitz
Using a global loader for transitions - StackBlitz
solid-router's implicit transitions discourage page partial loading fallbacks in favour of paint-holding the stale page while showing one central loading indicator.
I think most of what you're looking for can be done by forcing the Suspense to be recreated for each navigation by putting a
<Show when={location.pathname} keyed>
around it. You'll then see the fallback of the Suspense
instead of the old content