Solid router, suspense and navigate
I have 2 routes, let's say
/login
and /home
, the login file is small, loads in 1s, home file is big loads for 10s (because of dependencies).
In the case above initially going to /home
, it redirects as fast as it can to /login
.
The /login
file is loaded, but suspense still holds until the /home
file is loaded, then it shows /login
.
How can I make it show /login
just as soon as it loaded, not waiting for /home
?
(not solid start)
(Tried it in production build)12 Replies
One approach to achieve this in Solid.js is to adjust your App component to conditionally render components based on the loading state of your routes.
How to do that? How can I get loading state of route? And what do you mean about conditionally rendering components?
/login
Navigate - SolidDocs
Documentation for SolidJS, the signals-powered UI framework
The solid start example can work with plain vanilla
@solidjs/router
— you just have to replace the "use server"
sections with your style of authentication.
- have a query
value dedicated to holding the user/account information or undefined
- on unauthenticated access throw redirect
redirect - SolidDocs
Documentation for SolidJS, the signals-powered UI framework
GitHub
solid-start/examples/with-auth/src/lib/index.ts at f83526c45a65af6a...
SolidStart, the Solid app framework. Contribute to solidjs/solid-start development by creating an account on GitHub.
I'll check it out later, but point of this question wasn't authentication, but rather about suspense behaviour when loading bigger files with instant redirection
I'm thinking that you can tweak that by organizing the (route) layouts and preloads.
In Strello the
user
query will force the redirect
.
Meanwhile the root layout common across all routes deliberately accesses the user query
forcing the redirect to /login
(while itself remaining in place) when there is no authentication.
It's a matter of your implementation of getUser()
- being run as quickly as possible
- quickly deciding to throw the redirect.GitHub
strello/src/components/Layout.tsx at 9c9ae973d96cc045914e696757a1b5...
Contribute to solidjs-community/strello development by creating an account on GitHub.
GitHub
strello/src/lib/index.ts at 9c9ae973d96cc045914e696757a1b5f31efc6fa...
Contribute to solidjs-community/strello development by creating an account on GitHub.
Sketch:
I think the
Show
can do someting but I'll try it when I get back
Yeah so Show
doesn't actually change anything...
unless I do so
This code above achieves what I want. It doesn't even fetches /home
, so just shows /login
when it loads. I like this, I can prefetch /home
on my own. Without setTimeout
it doesn't work. I don't like that I have to do this with setTimeout
, because I'm not sure if this behavior will be consistent.
Your solution with createAsync
probably will work too, because getting account can take some time. But going back: authorization is not point of this question. What I mean is to force suspense to resolve when latest route is loaded, not all previously requested.
To visualize:
We have suspense on props.children
, which is current route component.
User first clicks button to go to /about
, this page is big, it takes 10s before it loads. So in first second of waiting, user gets bored by waiting and clicks button that navigates to /home
, which is very small, it takes 1s before it's loaded OR maybe it's even prefetched, so it takes no time to load it.
What actually happens is user is waiting for 9 more seconds, until he is redirected to /home
, even though it's been loaded this whole time. User changed his mind and doesn't want to go to /about
, he wants to go to /home
, but has to wait until/about
is loaded.
The /about
page is loading for 10s not because of asyncs or resources, but because it's size is big and network takes this time to fetch the js file and might have only static contentthe setTimeout bypass the transition
it will work as long as what you are doing is working now
What I mean is to force suspense to resolve when latest route is loaded, not all previously requested.The
navigate
isn't issued until the render. By that point in time the home
async operations have already been triggered and as such committed to. Given that you have one common Suspense boundary the login
async ops are just added to the same suspense queue and suspense does not complete until all ops have settled.
So one way to approach this is to ensure that both home
and login
have separate, non-overlapping Suspense boundaries. That way when you flip over to the login
render, the home
async ops aren't already queued up on the suspense boundary.
The Show
approach on the other hand simply ensures that the async ops are not committed to until it ensures that some precondition is met. In the context of the example the most obvious precondition for committing to loading home
is “are we authenticated yet”.
It just seems more relevant than implementing a separate “is this the initial render” mechanism.Okay, now it's clear, after removing suspense from <App> and putting it deeper - in each page - it works as expected
I avoided doing this
Protected
template, because I use vite-plugin-pages
and because there is no unnamed route group, this would look like /protected/home
. Tho I think this can be configured there with dirs
setting, but still, having routes represented in folder / file names with exceptions written out in different settings file would make it more confusing. So I think I'll switch to component routes and use this.
or tankstack router hmmm
but this issue is solved so thanks
nvm can make my own consistent rules with vite-plugin-pages
and onRoutesGenerated