Next.js Discord

Discord Forum

Race condition with optimistic useSWRMutation

Unanswered
Florian posted this in #help-forum
Open in Discord
I made an optimistic favorite button with useSWRMutation. If I click the button multiple times fast in a row, I sometimes get a race condition and the button toggles back to the opposite state.

How can I avoid this?

1 Reply

const { data } = useSWR<{ isFavoritedByUser: boolean }>(
    `/api/companions/${companionId}/favorites`,
    async (url: string) => {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error("Failed to fetch favorites info");
      }
      return response.json();
    },
    {
      revalidateOnFocus: false,
      revalidateOnReconnect: false,
      revalidateOnMount: false,
      revalidateIfStale: false,
      fallbackData: { isFavoritedByUser: initialIsFavoritedByUser },
      onError(err) {
        console.error(err);
        toast({
          variant: "destructive",
          description: "Failed to fetch favorites info. Please try again.",
        });
      },
    }
  );

  const { trigger } = useSWRMutation<{ isFavoritedByUser: boolean }>(
    `/api/companions/${companionId}/favorites`,
    async (url: string) => {
      if (!data) return;

      const response = await fetch(url, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ favorite: !data.isFavoritedByUser }),
      });
      if (!response.ok) {
        throw new Error("Failed to update favorite status");
      }
      return response.json();
    },
    {
      rollbackOnError: true,
      optimisticData: {
        isFavoritedByUser: !data?.isFavoritedByUser,
      },
      populateCache(result, currentData) {
        return {
          ...currentData,
          ...result,
        };
      },
      revalidate: false,
      onError(err) {
        console.error(err);
        toast({
          variant: "destructive",
          description: "Failed to update favorite status. Please try again.",
        });
      },
    }
  );

  function handleClick() {
    trigger();
    toast({
      description:
        "Companion " +
        (data?.isFavoritedByUser
          ? "removed from favorites"
          : "added to favorites"),
    });
  }