useSWRMutation optimistic UI with rapid mutations
Answered
Jersey Wooly posted this in #help-forum
Jersey WoolyOP
Hope SWR questions are OK here!
I'm using SWR in a situation where a user may rapidly update something, and I don't want to block them from making changes during mutation. Right now, I'm calling a server action to preform the mutation. It works fine in isolation, but if I trigger it rapidly (e.g. keep pressing a button quickly), the optimistic updates get stuck at the first one until all updates have gone through. How can I always keep the optimistic data fully up-to-date? Thanks!
useSWRMutation
(extremely rough prototype) trigger call:
Action:
I'm using SWR in a situation where a user may rapidly update something, and I don't want to block them from making changes during mutation. Right now, I'm calling a server action to preform the mutation. It works fine in isolation, but if I trigger it rapidly (e.g. keep pressing a button quickly), the optimistic updates get stuck at the first one until all updates have gone through. How can I always keep the optimistic data fully up-to-date? Thanks!
useSWRMutation
const { trigger, isMutating } = useSWRMutation(
weeklyEventsKey,
(_, { arg: { name, id } }: { arg: { name: string; id: string } }) =>
updateEventName(name, id)
);
(extremely rough prototype) trigger call:
trigger(
{
name: "Event - " + new Date().toISOString(),
id: events[0].id,
},
{
optimisticData(currentData: any) {
currentData[0].name = "Event - " + new Date().toISOString();
return currentData;
},
},
)
Action:
"use server";
import { db } from "@/db/drizzle";
import { eventsTbl } from "@/db/schema";
import { auth } from "@/lib/auth";
import { eq } from "drizzle-orm";
export default async function updateEventName(name: string, event_id: string) {
if (process.env.NODE_ENV != "development") return;
const session = await auth();
// console.log(session);
// if not auth kick out etc etc.
// 1500ms delay
await new Promise((resolve) => setTimeout(resolve, 1500));
await db.update(eventsTbl).set({ name }).where(eq(eventsTbl.id, event_id));
return true;
}
Answered by Jersey Wooly
nvm im dumb its a stateful mutation thing lol. Fixed with:
trigger(
{
name: "Event - " + new Date().toISOString(),
id: events[0].id,
},
{
optimisticData(currentData: any) {
// Create a new array to avoid mutation
const newData = [...currentData];
// Create a new object for the updated event
newData[0] = {
...newData[0],
name: "Event - " + new Date().toISOString(),
};
return newData;
},
},
)
3 Replies
Jersey WoolyOP
e.g. the UI only updated at the FIRST call, and then the last call (35.351Z). The in-between calls (33.733Z, 34.269Z, etc.) were never reflected in UI.
Also for the record, I understand why the requests are queued up after eachother and will only finish after all have completed (because otherwise oh god the race conditions), just that I want optimistic UI to always try to stay updated
Jersey WoolyOP
nvm im dumb its a stateful mutation thing lol. Fixed with:
trigger(
{
name: "Event - " + new Date().toISOString(),
id: events[0].id,
},
{
optimisticData(currentData: any) {
// Create a new array to avoid mutation
const newData = [...currentData];
// Create a new object for the updated event
newData[0] = {
...newData[0],
name: "Event - " + new Date().toISOString(),
};
return newData;
},
},
)
Answer