Next.js Discord

Discord Forum

useSWRMutation optimistic UI with rapid mutations

Answered
Jersey Wooly posted this in #help-forum
Open in Discord
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
  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;
              },
            },
          )
View full answer

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