Open brillout opened 2 months ago
I've created small minimum repo containing example of implementation without vike-react
:
https://github.com/UROjQ6r80p/vike-suspense-loading-ui
At first I thought either useTransition
or useDefferedValue
is required but it seems it's unneccessary and might lead to subtle bugs.
It seems that Vike by default stays on the current page for suspense based hooks (useAsync for example) IF there is no Suspense wrapper.
That's why I think it can be created based on conditional SuspenseWrapper
(similar to how Layout and Wrapper are currently implemented in vike-react
).
I suggest +loading.jsx
naming convention just like next.js does (https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming), or maybe +fallback.jsx
?
and so if there is +loading.jsx
setting in the folder, Suspense with fallback from +loading.jsx should be returned, or empty PassThrough
component.
The catch is that ideally for pages without +loading.jsx
(because creating tailored skeleton requires more effort and might not be desirable on every page) I suppose most people would like to use something like ngprogress to display loading indicator on top just like youtube/github and thousands of other sites do.
if a user wants to implement loading indicator with for example useAsync() then onPageTransitionStart
works without problems, but onPageTransitionEnd
does not wait for suspense based hooks, it fires immediately.
It can be easily mitigated by custom HOC wrapping Page like in my example (https://github.com/UROjQ6r80p/vike-suspense-loading-ui/blob/main/renderer/withTransitionEnd.jsx) or another meta setting.
But I think adding separate meta setting (something like onSuspenseTransititionEnd
for it is not ideal and could be confusing.
so my question to maintainers is, can onPageTransitionEnd
itself be changed so that it would wait for suspense based hooks just like it waits for +data.js
?
so my question to maintainers is, can
onPageTransitionEnd
itself be changed so that it would wait for suspense based hooks just like it waits for+data.js
?
I was also thinking that. Vike actually already awaits onRenderClient()
and after the promise resolves Vike calls onPageTransitionEnd()
. So all we need to do is to make onRenderClient()
await the transition.
It seems that Vike by default stays on the current page for suspense based hooks (useAsync for example) IF there is no Suspense wrapper.
Why is this the case? Why is useTransition
not required?
I this is true, it would mean that the loading bar would behave correctly, on pages with or without suspense.
Page with Suspense -> show the suspense fallback Page without Suspense-> show the loading bar
Isn't this the desired behavior? Why do we want to show the loading bar on a page that has suspense?
Why is this the case?
So it seems that, if there isn't any <Suspense>
boundary, then React first renders everything to its virtual DOM and flushes it to the real DOM in one batch. I think that makes sense.
Page with Suspense -> show the suspense fallback
Page without Suspense-> show the loading barIsn't this the desired behavior? Why do we want to show the loading bar on a page that has suspense?
Yea, if the page has suspense then I also think that we don't need to show the loading bar.
The only exception being Main <Suspense>
. In that case, the loading bar is shown until all await()
components are resolved.
It seems that Vike by default stays on the current page for suspense based hooks (useAsync for example) IF there is no Suspense wrapper.
I checked it again and I think it works only in dev mode, after everything is built and run in prod it does throw errror after client side navigation to the page with useAsync
hook: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.
I have tried it with my own example, and also vike-react
, so if I want to use useAsync
then there has to be <Suspense>
wrapper it seems (only in production, in dev it works fine)
Defer next page + loading bar
A neat page transition is to preserve the current page and defer showing the next page until it's fully loaded, while showing a loading bar (like YouTube or nprogress). I think it's already possible for the user to implement this?
How about we make this the default behavior?
Default
Currently,
vike-react
doesn't provide any default page transition strategy, but I think it should. (While enabling the user to override this default.)<Suspense>
How about pages that have suspense? (More precisely: when the next page has one or multiple
<Suspense>
boundaries.) In particular when usingvike-react-query
andvike-react-apollo
.With @nitedani we already have ideas about this (
withFallback()
and a new setting+Loading.js
).Main
<Suspense>
How about this: let the user declare the "main"
<Suspense>
boundary. As long as this main suspense isn't resolved then keep showing the old page with a loading bar. As soon as this main suspense is resolved, then show the next page (consequently showing all suspense boundaries that are still loading).For example, a product page would start to be shown to the user upon page navigation only after the product content of the page is fetched from the database.
In other words, it's blocking the rendering the next page. API example:
There could be several
await()
components for a single page. (Although, in the (vast?) majority of cases, the user would likely define only oneawait()
component.)I ain't sure how an implemention would look like, but IIRC React 18/17 introduced a new feature that was addressing this use case. (Start rendering the next page in a seperate virtual DOM while preserving the current page.)
No
<Suspense>
What should happen when there isn't any
<Suspense>
boundary? (Which is also possible withvike-react-{query,apollo}
when the user doesn't useuseFallback()
.) I guess this is the default behavior, i.e. defer showing the next page + loading bar.See also