ibrahimyaacob
ibrahimyaacob•12mo ago

how do i set loading on mutate ?

I came from react query background where this can be set easily with the onMutate listener.
45 Replies
erquhart
erquhart•12mo ago
The mutation returns a promise, you can use that for loading status.
sshader
sshader•12mo ago
You can also add an optimistic update that sets a particular query to undefined which is treated as loading
useMutation(api.foo.myMutation).withOptimisticUpdate((localStore, args) => {
localStore.setQuery(api.foo.myQuery, {}, undefined)
})
useMutation(api.foo.myMutation).withOptimisticUpdate((localStore, args) => {
localStore.setQuery(api.foo.myQuery, {}, undefined)
})
dataloader
dataloader•11mo ago
@erquhart this only 'half' works, because it doesn't tell you if a refetch is 'in-flight', only that the mutation is done (and presumable a refetch is about to occur). Is there a solution to the second half of that process?
erquhart
erquhart•11mo ago
It isn't really refetching, queries update reactively via websockets. If you can share your use case and the behavior you're trying to avoid/achieve, we can help solution more.
dataloader
dataloader•11mo ago
@sshader it seems to me there are three steps: 1. mutation starts 2. mutation finishes 3. refetch of relevant query starts (this may or may not be known via the wss connection) 4. refetch of relevant query finishes 1 you can trigger via withOptimisticUpdate 2 you can trigger via promise resolution of mutation locally 3 (not possible with client APIs) 4 (not possible with client APIs) @erquhart it may be true that the wss connection does not notify when an updated query is coming, but is definitely knows when it received a new one and not even that event is made visible via client library
erquhart
erquhart•11mo ago
A use case would help the conversation here.
dataloader
dataloader•11mo ago
one sec check the "Saved"/"Saving..." badge in the top right. https://chat-convex.vercel.app/
dataloader
dataloader•11mo ago
dataloader
dataloader•11mo ago
this is currently being done via useConvex().connectionState().hasInflightRequests but that applies to all queries, which wouldnt work if there are others not relevant to what's being "Saved" here
dataloader
dataloader•11mo ago
here's the whole react (nextjs client) component. the only thing missing from this code are my apis, which can be discerned from the code itself
erquhart
erquhart•11mo ago
hmm
dataloader
dataloader•11mo ago
I suppose I could solve this by creating a custom hook with a ref of the object coming out of useQuery, checking for Object.is in a useEffect and then a callback, say, onChange when it does. But that's a bit rube goldberg. I thing the wss stream should tell us this more simply/
erquhart
erquhart•11mo ago
Your saving indicator is just showing whether the data has persisted, right? As a user, I expect a "saved" indicator to mean "you can close the application right now and lose nothing". With that definition in mind, you can just use the promise returned by the mutation.
dataloader
dataloader•11mo ago
Yes, persisted. Great point. Let's say instead a "latest" badge. That's really what I'm talking about it seems For saved I agree this is solveable with the mutation promise! Thanks for pointing that out
erquhart
erquhart•11mo ago
Rather than a latest badge, you'll generally want to use an optimistic update to bridge the UI gap between mutation and query update
dataloader
dataloader•11mo ago
Well, I think this comes down to the question "is the data shown the live, correct data in the db", because the optimistic update could be wrong. and for trust/reliability reasons, I would only want to tell users the absolute definite truth!
erquhart
erquhart•11mo ago
If you're talking multiplayer and assuring the user that they're seeing the latest, you're sort of leaning on the system to provide that assurance. I would fallback to "is it connected" - if the connection is live, trust Convex to keep it realtime and show the latest. If the connection is not live, that's where you want to signal to the user that there's an issue, which is a common pattern in realtime apps.
dataloader
dataloader•11mo ago
Imagine on a slow connection, it says "saved" and then a second later updates to something different! Annoying/scary
ballingt
ballingt•11mo ago
I'm jumping in without having read everything, but in the React client there is a guarantee that by the time the promise for a mutation resolves the query results will have already updated
dataloader
dataloader•11mo ago
Agree we cannot know things from other users before they arrive. We're against physics at that point >I'm jumping in without having read everything, but in the React client there is a guarantee that by the time the promise for a mutation resolves the query results will have already updated Oh really, that's great! and cool I wonder what the thinking behind the other option is / if there's a reason to know persistence prior to that
ballingt
ballingt•11mo ago
This isn't a universal property of the WebSocket protocol, you could write a client that did not guarantee this. But the React client will wait to resolve the promise until the logical timestamp of the completed mutation has passed for the querie results.
dataloader
dataloader•11mo ago
i guess that's one round trip to convex isn't it! it immediately checks for who needs updates, which very well could include the one submitting the transaction. Do i have that right? (i.e. convex doesn't reply over the wss channel to the mutation except also with the new data if there is a subscription to relevant changes) Someone who knows the backend codebase well could probably find that
ballingt
ballingt•11mo ago
There is actually a mutation response first (thsi returns the return value of the mutation) and then a query, so call it 1.5 round-trips?
No description
ballingt
ballingt•11mo ago
If you have slow queries this could be noticeable, and we've talked about having two different promises; one that resolved on the mutation finishing, and one that resolves once all queries have updated. But for simplicity we went with the second, more useful IMO one.
dataloader
dataloader•11mo ago
interesting. Thanks for looking into that! Speaking freely, this is the kind of stuff I'd love to see exposed (e.g. via a meta subobject) from the react hooks. Sometimes the full control is helpful. If I wanted this, is the best way to write my own hooks or patch the convex/react hooks?
ballingt
ballingt•11mo ago
GitHub
convex-js/src/browser/sync/request_manager.ts at 30677dee6d5f9acc90...
TypeScript/JavaScript client library for Convex. Contribute to get-convex/convex-js development by creating an account on GitHub.
ballingt
ballingt•11mo ago
What you're doing here is perfect, raising the issue along with a use case. This particular one is fairly deep so hard to patch around without forking the client.
dataloader
dataloader•11mo ago
Actually, on that note. I'd love full-on escape hatches too. like exposing the web standard ws connection via useConvex (inside some hidden prop to not clutter the experience for the regular user). Would that be possible you think?
ballingt
ballingt•11mo ago
IMO I'd want to see an application with slow queries before complicating the API with this additional resolve callback, but when we made the decision it was very much "this is what people will want first, if they get fancy they can talk to us." Balancing simplicity with power is obviously the tradeoff.
dataloader
dataloader•11mo ago
I could even imagine throwing the ws messages at a logging/tracing framework. to allow debugging issues specific to convex (along with or aside other issues caused by me and my team) definitely understand that. there is a lot to build. TODOs are better than unfinished product!
ballingt
ballingt•11mo ago
Re exposing the WebSocket inside the JavaScript, it's be frustrating for us for more of the protocol bugs we observe in production not to be ours, despite coming from the client we wrote. You can use a normal WebSocket and reverse engineer the protocol, it's pretty stable. Several people have done this, usually to write clients in other languages. We just ask that you use a different client ID header. Absolutely, registering callbacks for this totally makes sense (and it's not so much reverse engineering now that both sides are open source!)
dataloader
dataloader•11mo ago
That makes sense. I'd probably shy from reverse engineering. Stability first. But good to know it'd be possible!
ballingt
ballingt•11mo ago
We might not be fully protecting the WebSocket object but we would if we could, it's just making stuff really private is a hassle. But anyone can fork the code and just pretend to be the same client so it's all somewhat accessible. it's just helpful for debugging to be able to say "oh that's not our client, that's someone else" and not wake people up at night for it
dataloader
dataloader•11mo ago
Also, while I have you, is there any public docs on when local convex server for dev will be possible? I tried running the mac aarch64 backend binary (I love how simple this was!), but the client libraries had a few hardcoded things in the way so I quickly gave up. I don't like eating up paid bandwidth locally (also I wouldn't put local bugs with infinite request loops entirely past me haha)
ballingt
ballingt•11mo ago
We're making progress on this but I don't think there's anything official yet
dataloader
dataloader•11mo ago
Month or more probably?
ballingt
ballingt•11mo ago
@CodingWithJamal and @Web Dev Cody hoave both made videos on it
dataloader
dataloader•11mo ago
Ok. looks like just convex dev might do some extra magic to pass up the errors i saw (first one being hardcoded check for hostname endswith(".convex.cloud")), as opposed to use the raw binary prebuild. https://www.youtube.com/watch?v=RWy-3G7e6Xc
ballingt
ballingt•11mo ago
Not sure, but it's definitely our intention to do this! The hardcoded check for .convex.cloud also allows localhost. That's a great point, we need to fix this! the point was to catch bad URLs as soon as possible, but we can't have our JS client (I think that's the only one that does this?) hardcoded to only allow .convex.cloud URLs 🫢
dataloader
dataloader•11mo ago
PR removing the *.convex.cloud check https://github.com/get-convex/convex-js/pull/9 @ballingt
GitHub
allow self-hosted (arbitrary) convex hostname (not just `*.convex.c...
Thanks. If I've missed something, please feel free to overtake this PR with your own.
ballingt
ballingt•11mo ago
Nice, thank you! We were discussing how to still provide some quick validation, one idea is a better initial health check. I'll follow a plan in the PR probably by Monday.
ballingt
ballingt•11mo ago
Relatedly, custom domain names are coming soon (according to https://discord.com/channels/1019350475847499849/1019372556693815418/1220856197725294643)
Discord
Discord - A New Way to Chat with Friends & Communities
Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.
adam
adam•10mo ago
Does the "allow any URL" improvement released as part of https://news.convex.dev/announcing-convex-1-12/ allow for using a custom domain? Can I use my own domain and setup a CNAME to point to my *.convex.cloud domain? Should this work ok with subscriptions?
Convex News
Announcing Convex 1.12
We’ve had a busy month, and we have a bunch of different improvements to share! Support for Svelte, Bun, and Vue! We have a few more logos under our quickstarts section – we've added guides for Svelte, Bun, and Vue including our first community-maintained client library! HTTP action response streaming
jamwt
jamwt•10mo ago
Not yet. That requires support from our traffic infrastructure. But it’s on the roadmap!
adam
adam•10mo ago
Good to know, thanks Jamie!

Did you find this page helpful?