Run route.load and access return value only once when navigating to page
Hey, I am working on a route where before rendering the route, basic middleware needs to run to check if the client should have access to the route by checking the query parameters of the url and redirect if not. During this check I need to decrypt a query parameter, which can only be done on the server as I don't wanna share my secret key used to decrypt it with the client but I also would like to pass parts of the decrypted data to the route component to render on the page.
Here is a small example:
To do this I would like the
route.load
function to run getEmail
once to do the middleware checks and decrypt the data to return parts of it to the page component so that the server function getEmail
only needs to run once when directly loading the page (and directly render the email without calling the server function once the page has loaded on the client) or when navigating to the page from a different route (only run server function).
How can I do this with solid start? Right now it loads the page and the email isn't rendering at all as it seems like the query parameters are empty when getQuery
is called for some reason?
Also, the server function returns a redirect to /login
, as it should when the query parameters don't match but it doesn't navigate to /login
, I guess because its a status code 200 response instead of 3xx.10 Replies
Using
redirect
requires wrapping the function with cache
or action
, in this case you'll want to use cache
getQuery
will only contain the values you need when the page is being server rendered
When getQuery
is being invoked by the client during a client navigation you won't have the query params included with the request
You probably want to take the state as an argument to the function and then read the query parameters from the router and pass them inFYI: A route load function is passed a
{ params, location, intent }
argument. location.search
contains the query string which you could then pass to a server function as an argument. Server side you can feed that string into URLSearchParams
for easier access.
The other subtlety is that the redirect won't happen when the load
is run; it can't because load
may run for an opportunistic preload.
The redirect happens the moment a component tries to consume the cache
that “experienced” the redirect with a createAsync()
.MDN Web Docs
URLSearchParams: URLSearchParams() constructor - Web APIs | MDN
The URLSearchParams() constructor creates and returns a
new URLSearchParams object.
Thanks! I updated my code based on both of you guys answers and now it writes the email into the returned html when directly loading the page and when navigating to it on the client so it seems like this issue got solved.
I noticed that the server function is running twice, doesn't matter if its client side navigation to the page or directly loading the page. Its running once when navigating/rendering and once after for some reason. Would it be possible to prevent this somehow?
Here is the updated example:
And also, how can I get the redirect to work now?
Hypothetically the cache is considered fresh for 10 seconds, so even if the
load
runs multiple times (which it will) the function wrapped by cache
should be safe.
One possibility is that something is forcing an invalidation of that cache
making it rerun.
Is the double call happening only in the redirect case or also in the allow case?its running twice for both redirect and allow
this is when directly loading the page, its running once when server rendering the page and once from the client
Fresh install of SolidStart "basic" with the following modification:
These results would lead me to conclude that you have something else at work here.
Tried to find the issue starting with the basic example and adding stuff over slowly and it looks like because I import the server functions like getEmail from a seperate file it doesn't work, specifically because I made the whole file "use server" instead of each funcion specifically
Don't know if this is intentionally designed to not work like setting "use server" on each function but it kinda sounds like it should work the same in the docs tbh https://docs.solidjs.com/solid-start/reference/server/use-server
at least if it isn't a route where I'm doing that
Things still work as expected with this partitioning:
It seems like this solved all my issues I'm having right now. Thanks @Brendonovich and @peerreynders for your help!