Can cache be manually set?
Say I have a
export const getList = cache(...)
and I access the list using createAsync
in multiple places in the app
If a user chooses to delete the entire list in some section of the app and the request succeeds, the expected result for the list is now to be empty
To my understanding with the current model, the way to update the list to be empty would be to revalidate
it, probably in an action
, which would trigger another call to the server to get the new list (which is empty)
but say I want to not go to the server to get the obvious empty-list result. Is there a way I can manually set the list to empty?
I had thought I could use cache.set()
to do this, but upon using it nothing seems to happen (at least reactively)
I know it is frowned upon to want to manually mutate state in the UI and not re-ask the server, but I can think of a few scenarios where this is harmless and beneficial.
basically, I am wondering if there is an equivalent mutate()
function from createResource
for createAsync
11 Replies
I had thought I could use cache.set()
to do this
The issue with this approach is that it destroys a known valid, perhaps stale value without a means to reinstate it when things go wrong and more importantly there is no way of telling that the set value is only a preliminary value.
which would trigger another call to the serverWhich Start solves with Single-Flight Mutations. The universal solution is to display the preliminary value held by useSubmission while the action is in-flight. This also creates to opportunity to convey to the user that the value shown is preliminary, i.e. optimistic. Examples: https://stackblitz.com/edit/solidjs-templates-7u2yad?file=src%2Fapp.tsx https://stackblitz.com/edit/vitejs-vite-jiumjg?file=src%2FApp.tsx
peerreynders
StackBlitz
solid.js action cache interplay - StackBlitz
A Solid TypeScript project based on @solidjs/router, solid-js, typescript, vite and vite-plugin-solid
Nyi Nyi Lwin
StackBlitz
solid js - useSubmission - StackBlitz
Next generation frontend tooling. It's fast!
GitHub
solid-router/README.md at a2652b4eab6576db78e6371e5c0aa45eea85d98d ...
A universal router for Solid inspired by Ember and React Router - solidjs/solid-router
To my knowledge, Single Flight Mutations should be called "Single Flight Redirects" as they only save you the extra call to the server to redirect not save the extra call to get the new cache value
If there is an example of using an action to mutate the value on the server, then on return mutate the cache value on the client, all in one go, then I have not seen it, and this would be my goal (to save on an unnecessary server call for a value that I already logically know)
and yes I know cache.set() would be an anti-pattern, but I am simply trying to understand what it is supposed to do, because in using it based on my assumptions I dont see it doing anything (so either its bugged, or I just dont understand what it is supposed to do)
and yes I could use useSubmission, but again the problem I am trying to solve is not optimistic updates necessarily, it is more so trying to stop an unnecessary call to the server
then I have not seen itIf you'll look at
saveNote
on the Notes example you'll notice that there are redirect
s in the "use server"
section.
The response returned already has Location
header set.
That means that the Start server runtime can match the URL to the route and run the loader server side to assemble the response body and set up the single flight header to be extracted on the other end.GitHub
solid-router/src/data/action.ts at a2652b4eab6576db78e6371e5c0aa45e...
A universal router for Solid inspired by Ember and React Router - solidjs/solid-router
GitHub
solid-router/src/data/response.ts at a2652b4eab6576db78e6371e5c0aa4...
A universal router for Solid inspired by Ember and React Router - solidjs/solid-router
GitHub
solid-start/examples/notes/src/routes/notes/[id]/edit.tsx at 914647...
SolidStart, the Solid app framework. Contribute to solidjs/solid-start development by creating an account on GitHub.
GitHub
solid-start/examples/notes/src/lib/api.ts at 914647c9d122cfb3dd974d...
SolidStart, the Solid app framework. Contribute to solidjs/solid-start development by creating an account on GitHub.
what it is supposed to doIt's not clear to me that
cache.set()
is ever going to be documented; for the time being I'm treating it as internal
.
is more so trying to stop an unnecessary call to the serverI think that largely depends on: - issuing the redirect in the action server side - having the route loader set up so that it can assemble the response body of the single-flight response just knowing the redirect URL.
This was super helpful ❤️
I was using cache() but not on the server ('use server') instead I was calling an api endpoint from the client
I also did not have route loaders (I thought these were just for preloading on hover)
Looks like if you do not specify
redirect()
with revalidate
then the route will invalidate all cache in use. But its still cool that all of these cache values will get their new values through the single response
So in order to be more "narrow" with what is invalidated you can specify inside redirect(..., { revalidate: ... })
The only awkward thing to me is if I do not want to redirect to another page, and instead stay on the same page after the action, I seem to have to specify in redirect() to go to the page I am already on.I also did not have route loadersI only realized the connection today when I started dissecting the example. It's the only possible way the server could determine what data it needs to send back, just based on the URL.
will invalidate all cache in use.Yeah, I forgot about that …
I seem to have to specify in redirect()
to go to the page I am already on.
… to convey intent better just use reload()
instead (… just noticed that).it seems I was mistaken, I thought using reload and redirect were correctly doing a single flight mutation according to the logs I have on my server
but I looked over to the network in the browser and it is now not single flight
when I do not specify reload or redirect it correctly does single flight (but invalidates all cache)
somehow I am not able to do both single flight mutation AND specify a specific cache to invalidate...
maybe my keys are wrong?..
I haven't used single flight mutations "in anger" yet, so my narrative could be off.
Sounds like for some reason it decides abandon single-flight. I'd start by console.logging the route loader to see if its behaviour meets expectations on the server side.
There is one inconsistency between the documentation and the code. Usually the documentation is wrong but there is a first time for everything.
Try
throw
ing the redirect/reload.https://github.com/sabercoy/solid-single-flight
this summarizes what happens in 4 different scenarios
1. calling an action that does not return or throw anything will invalidate all cache in single flight
2. calling an action that throws a reload and revalidates ALL caches does not do it in single flight (each cache gets a _server call)
3. calling an action that throws a reload and revalidates ONE cache does not do it in single flight (that one cache gets a _server call)
4. calling an action that throws a redirect will redirect as normal
for whatever reason, when trying to specify a specific cache to revalidate, it shrugs and says "okay, but not gonna do it in a single flight"
GitHub
GitHub - sabercoy/solid-single-flight
Contribute to sabercoy/solid-single-flight development by creating an account on GitHub.
Compare what you have:
with the example
The example only consumes one single cache point, it's designed to load with a single request.
Your observation with (1.) is a good thing because the fact that you are consuming multiple cache points doesn't break things.
(2.) Should give you pause. You were trying to be helpful by being specific (while in principle duplicating 1.) but your expectations weren't met.
The next thing to try:
… and single-flight is back. This should give rise to a new hypothesis:
revalidate
is an opt-out of single-flight (SF) because SF relies completely on the route loader to determine what to send back. revalidate
doesn't tell SF what to put into the response body, instead it says "don't bother doing the full route load, lets instead fall back to sorting things out in the standard fashion".
The trade off is that SF will tend to over-query but that's nothing unusual in the world of "stateless" servers; if server side over-query is an issue then you fall back to using more requests based on the client's assumptions.
Now these trade offs may change in the future but there could be very good reasons that they currently are, what they are.I did notice this in the docs, but I figured the docs were just trying to show a minimum example, it never claimed that the load function could only return one cache, I looked at the load function like "it returns everything you need for this route"
If route.load were only for one cache point, wouldnt that be very limiting?
as far as conclusions from all of this I would have to go with what you stated:
revalidate
is an opt-out of SF
and, on the flip side, SF is an opt-out of fine-grained-querying on the server side (in other words, if you want SF, you will need to make a call for everything in route.load regardless of if you want to or not)
It does appear, not matter what you do, there will be over-querying in one form or another on the client or server
In the end my goal was just to better understand the behaviors, limitations, and intent behind these APIs so that I could design my app accordingly. Thanks so much for helping me understand!