optimistic update for complex data structure
I am making a recipe website with the t3-stack and I made something that "works" but is not very fast. I am kind of new to web dev with the t3 stack and I need some help
112 Replies
this is my prisma schema
This is kind of the structure I want, but I want it to be optimistic
how would I do this
this is how I started but I dont know what I'm doing wrong...
and I want to learn when to use query vs mutation
each recipe has a title and desc and a collection of steps and ingredients,
and to instantly add the new steps
or ingredients
please help
y no one help me
Need bit more details here … slow doing what ? Is it initial page load, anything that’s to do with making API calls, or just unreal when you click on buttons? I’m suspecting the last one, in that case it’s usually unnecessary re-rendering happening with useEffect or sth…
I mean the time it takes for the api call to update the data, since I mostly test on school wifi the delay is unbearable. I want it to be optimistic
if you want to see the original recipe form, please tell me (its a mess)
for this one I followed the optimistic data code snippet on t3
but I dont exactly understand it
i tried looking for videos explaining it but I dont know how to apply it to my own use case
I don't know if it works on nextjs but theres this:
https://medium.com/@prithvi128717/creating-optimistic-updates-in-ui-with-react-jss-c5769b37b945
Medium
Creating Optimistic Updates in UI with React.js’s
Optimistic updates are a powerful technique in modern web development, especially when it comes to improving the user experience. By…
id rather not use useOptimistic, and im not usnig server actions, I am using trpc + app router
Got you, what is your backend? Assuming you are using prisma and calling planescale or sth?
I am using prisma + planetscale and trpc, thats what I know of
Right… have you checked if you are making a connection every time you make a call?
this is generated with the create-t3-app
and this is how it is used
Looks good to me ..
I mean that shouldnt be an issue since I didnt touch it
When you say slow, is it like a few seconds for 300ms+?
I am doing this locally but on a vercel deployment its a bit slower, and the way I do it makes it inconsistent
it said there were 15 but actually there were 16
yk what forget it
It looks quite snappy to me … 😅
yes but not instant, i'll show you an example real quick of what I mean
you can see the number updating instantl, while the state of the mutation is still loading
Right so it is optimistic update then .
yes
It looks like you can use this same pattern? Instead of onSuccese, update the state onMutate and validate the state again onSettled and re-render ui if it failed
this is how Ive tried to do it just for the title
but it doesnt work
this is the collapsed thing btw
What’s this await call? That’s blocking for sure, and you are getting prevRecipie from backend . Probably better to hold that state within the component ..?
im doing the same thing like here
Ok.. doesn’t async await just defeat the purpose of onMutate? You don’t want to block any process with await but just to run the process as fast as it can..?
bro, idk what im doing, i just coppied from this age, https://create.t3.gg/en/usage/trpc#optimistic-updates
Why are you using onMutate here? You shouldn't need this at all
idk bro
Haha , I’m not react query wizard either so idk either …
lol
You need to go do a lot more research and effort into learning this stuff yourself
Go read the docs on trpc mutation ls, optimistic queries, etc.
I see where you got that code from, but you're using it correctly to do what you want. We also can't see your entire component so it's impossible to know what's actually going on
that is the entrie component
oh you mean the old one
its too large to send as text message
or image
if not use mutations how do I onClick call backend
useQuery must be in body of component
If you want to manually trigger a query, use a mutation
If you want the query to run automatically, use query
Can I also c utils.recipie function?…
its a trpc route
yes, thats why im using mutation
If you're okay with a query being called automatically and want to also manually trigger it, then yes you can use a utils function
Also
You're using
useEffect
horribly wronghow so
Go read the documentation on useEffect
ok but how am I using it wrong
how else would I update the title when the recipeData loads
Your using it to set state from a stateful action
Put it in the
onSuccess
of the queryWhere are you updating a state of recipieData? Can’t seem to find here
Yep
This is as instant as your going to get btw
ik
Oop, not that video but you know what I mean
yep
but even without the use effect that doesnt explain why the update is not wokring
Wym not working
Wld it make sense to run setTitle () under onMutate ?
No cause he's doing that anyways with ... recipes
when I press the button it should run the updateRecipe
But isn’t he making a TRPC call and call backend to block the process before he returns value from onMutate? Thought that’s where the delay is from …
this is the new one
the old one is different and is what I showed in the video with the delay
delay is just server delay
Bruh your going to need to learn how to debug
im explaining to @omotto
No I'm talking about in general
ok
Start putting in some console logs, see what you're backend is getting back, verify your backend is working as Intended, and just keep narrowing down the problem
You want to figure out what little piece is not doing what you expect
Rn we have no idea if your server is getting the wrong data, setting the wrong data, returning the wrong data, etc
All of which you can figure out trivialy
the backend is working as it did work with the previous version of the recipe form, this is causing the problem
There is your answer to this whole thread
Your not passing what key you want the data from
You don't never need that though lmao
lol …
You already have it
is there not supposed to be a type error
Don't use it regardless
You literally have the data like 3 lines up
works flawlesly now
recipieData IS previousRecipe
yea
Okay still don't use that lmao
what else do you recommend I use
Directly reference recipe data
?
That’s what I’ve been trying to say too ! lol
🤦
Previous data === recipe data
So don't define a previous data variable
Don't call your getdata function
Just replace previousRecipe with recipeData
prev recipe is just for the id userId and opened at so that typescript doesnt yell at me
My brother in Christ
Send your onMutate as a code snippet
Please for the love of all things good stop sending code screenshots
And send inline code snippets
There you go
You got it now
but I need to keep the prevRecipe if an error occurs to rollback
since the getQ.setData() updates the recipeData
You still are
No
in the cache
Nope
Try it
Your still returning the old data
This is where you need to read react documentation and understand what's going on under the hood
this is the snippet that is on the create.t3.gg website and which I followed
Or console.log everywhere to understand what’s happening 😅
Lol
When you call setData, it's calling a setState under the hood
So recipe data is changed NEXT RENDER not during the current execution of your function
oh yeaaa
The reason those tutorials use the getData method is that their assuming you have the state at a higher level in the component tree and don't actually have access to it directly like you do
Or/and because it's much simpler to show
so is this how I would go about implementing adding and updating steps and ingredients?
Now, since you're using your current renders data, you don't even need to use the await. You can just use void and let that whole chain run faster
I suppose yeah
Ehhhhh
Actually scratch that
You still need the await since it's technically a race condition
imma return to this thread when I have more time to implement the steps, and after that adding ingredients is just copy-paste
thx for the help and explanations @Josh @omotto
To optimistically update the recipeData the new step must have an id, but that id is generated after it is created; but this onMutate is running before it is created, is there any way to do this or do I have to start generating the ids on the client side?
this is the step.create route btw:
usually prisma generates it when the step is created
with the thing I added it is not optimistic, the new step is rendered when the succes toast is triggered which is on the on succes here
You shouldn't generate it client side, as that's just got a good idea from a security standpoint
You could use a temporary id and on success overwrite the temporary one with the real one
yea, the temporairy one is techincally blank, and ill make it that you cant edit it untill it has a valid id, but I want it to show up instantly so that I can run a check and make it uneditable
am I using utils.recipe.getQ.setData() wrongly here?