typescript 使用tRPC的乐观更新突变,React-query导致 Flink 更新

0yg35tkg  于 2023-04-22  发布在  TypeScript
关注(0)|答案(1)|浏览(128)

我目前正在使用tRPC useMutation React-Query钩子实现乐观更新,它似乎运行正常。然而,我遇到了一个问题,在更新数据时,响应会快速更新新列表,但在几毫秒后恢复到旧值,然后最终返回到新值。我不确定我可能做错了什么。下面是我的代码。

import { api } from "@/utils/api";
import type { Category } from "@prisma/client";

export const useCategoryActions = () => {
  const utils = api.useContext();
  //Queries
  const list = api.category.list.useQuery();

  // Mutations
  const update = api.category.update.useMutation({
    onMutate: (variables) => {
      // Cancel any outgoing refetches (so they don't overwrite(race condition) our optimistic update)
      void utils.category.list.cancel();
      const previousQueryData = utils.category.list.getData();

      const newCategory: Category = {
        id: crypto.randomUUID(),
        name: variables.name,
        slug: variables.name,
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      utils.category.list.setData(undefined, (oldQueryData) => {
        if (oldQueryData) {
          const filteredData =
            oldQueryData.filter((item) => item.slug !== variables.slug) ?? [];
          const elementIndex =
            oldQueryData.findIndex((item) => item.slug === variables.slug) ??
            -1;

          filteredData.splice(elementIndex, 0, newCategory);

          return filteredData;
        }
      });

      // return will pass the function or the value to the onError third argument:
      return () => utils.category.list.setData(undefined, previousQueryData);
    },
    onError: (error, variables, rollback) => {
      //   If there is an errror, then we will rollback
      if (rollback) {
        rollback();
        console.log("rollback");
      }
    },
    onSettled: async (data, variables, context) => {
      await utils.category.list.invalidate();
    },
  });

  return {
    list,
    update,
  };
};

存在一个潜在的解决方案,但它似乎无效,可能是由于不正确的实施。

import { useRef } from "react";
import { api } from "@/utils/api";
import type { Category } from "@prisma/client";

export const useCategoryActions = () => {
  const utils = api.useContext();
  const mutationCounterRef = useRef(0);
  //Queries
  const list = api.category.list.useQuery();

  // Mutations
  const update = api.category.update.useMutation({
    onMutate: (variables) => {
      // Cancel any outgoing refetches (so they don't overwrite(race condition) our optimistic update)
      void utils.category.list.cancel();
      const previousQueryData = utils.category.list.getData();

      const newCategory: Category = {
        id: crypto.randomUUID(),
        name: variables.name,
        slug: variables.name,
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      utils.category.list.setData(undefined, (oldQueryData) => {
        if (oldQueryData) {
          const filteredData =
            oldQueryData.filter((item) => item.slug !== variables.slug) ?? [];
          const elementIndex =
            oldQueryData.findIndex((item) => item.slug === variables.slug) ??
            -1;

          filteredData.splice(elementIndex, 0, newCategory);

          return filteredData;
        }
      });

      // Increment the mutation counter
      mutationCounterRef.current++;

      // return will pass the function or the value to the onError third argument:
      return async () => {
        // Decrement the mutation counter
        mutationCounterRef.current--;
        // Only invalidate queries if there are no ongoing mutations
        if (mutationCounterRef.current === 0) {
          utils.category.list.setData(undefined, previousQueryData);
          await utils.category.list.invalidate();
        }
      };
    },
    onError: async (error, variables, rollback) => {
      //   If there is an errror, then we will rollback
      if (rollback) {
        await rollback();
        console.log("rollback");
      }
    },
    onSettled: async (data, variables, context) => {
      // Decrement the mutation counter
      mutationCounterRef.current--;
      // Only invalidate queries if there are no ongoing mutations
      if (mutationCounterRef.current === 0) {
        await utils.category.list.invalidate();
      }
    },
  });

  return {
    list,
    update,
  };
};
yhxst69z

yhxst69z1#

这里是工作解决方案

import { useCallback } from "react";
import { api } from "@/utils/api";
import type { Category } from "@prisma/client";

export const useCategoryActions = () => {
  const utils = api.useContext();

  //Queries
  const list = api.category.list.useQuery(undefined, {
    select: useCallback((data: Category[]) => {
      return data;
    }, []),
    staleTime: Infinity, // stays in fresh State for ex:1000ms(or Infinity) then turns into Stale State
    onError: (error) => {
      console.log("list category error: ", error);
    },
  });

  // Mutations

  const update = api.category.update.useMutation({
    onMutate: async (variables) => {
      // Cancel any outgoing refetches (so they don't overwrite(race condition) our optimistic update)
      await utils.category.list.cancel();
      const previousQueryData = utils.category.list.getData();

      const newCategory: Category = {
        id: crypto.randomUUID(),
        name: variables.name,
        slug: variables.name,
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      utils.category.list.setData(undefined, (oldQueryData) => {
        if (oldQueryData) {
          const filteredData =
            oldQueryData.filter((item) => item.slug !== variables.slug) ?? [];
          const elementIndex =
            oldQueryData.findIndex((item) => item.slug === variables.slug) ??
            -1;

          filteredData.splice(elementIndex, 0, newCategory);

          return filteredData;
        }
      });

      // return will pass the function or the value to the onError third argument:
      return () => utils.category.list.setData(undefined, previousQueryData);
    },
    onError: (error, variables, rollback) => {
      //   If there is an errror, then we will rollback
      if (rollback) {
        rollback();
        console.log("rollback");
      }
    },
    onSettled: async (data, variables, context) => {
      await utils.category.list.invalidate();
    },
  });

  return {
    list,
    update,
  };
};

相关问题