使用 React Query 通过一个请求修补多个 ID

Patch multiple id's with one request with React Query

我有一个非常基本的应用程序原型,可以用来预订座位。用户选择 seat/seats,点击书籍,带有 available: false 的补丁请求被发送到假的 api (json-server),带有 React Query,库使请求无效并立即显示来自服务器的响应。

数据库结构如下所示:

{
  "hallA": [
    {
      "id": 1,
      "seat": 1,
      "available": false
    },
    {
      "id": 2,
      "seat": 2,
      "available": true
    },
    {
      "id": 3,
      "seat": 3,
      "available": false
    }
  ]
}

选择、预订座位的逻辑如下所示:

const App = () => {
  const { data, isLoading } = useGetHallLayout("hallA");
  const [selected, setSelected] = useState<
    { id: number; seat: number; available: boolean }[]
  >([]);

  const handleSelect = useCallback(
    (seat: { id: number; seat: number; available: boolean }) => {
      const itemIdx = selected.findIndex((element) => element.id === seat.id);

      if (itemIdx === -1) {
        setSelected((prevState) => [
          ...prevState,
          { id: seat.id, seat: seat.seat, available: !seat.available },
        ]);
      } else {
        setSelected((prevState) =>
          prevState.filter((element) => element.id !== seat.id)
        );
      }
    },
    [selected]
  );

  const takeSeat = useTakeSeat({
    onSuccess: () => {
      useGetHallLayout.invalidate();
    },
  });

  const sendRequest = useCallback(() => {
    selected.forEach((item) =>
      takeSeat.mutateAsync({ id: item.id, hall: "hallA" })
    );
    setSelected([]);
  }, [selected, takeSeat]);

  return (
    <>
      {!isLoading && (
        <ConcertHall
          layout={data}
          onSeatSelect={handleSelect}
          activeSeats={selected}
        />
      )}
      <button disabled={isLoading} onClick={sendRequest}>
        Take selected
      </button>
    </>
  );
};

查询如下所示:

export const useGetHallLayout = (hall: string) => {
  const { data, isLoading } = useQuery(["hall"], () =>
    axios.get(`http://localhost:3000/${hall}`).then((res) => res.data)
  );
  return { data, isLoading };
};

export const useTakeSeat = (options?: UseMutationOptions<unknown, any, any>) =>
  useMutation(
    (data: { hall: string; id: number }) =>
      axios.patch(`http://localhost:3000/${data.hall}/${data.id}`, {
        available: false,
      }),
    {
      ...options,
    }
  );

useGetHallLayout.invalidate = () => {
  return queryClient.invalidateQueries("hall");
};

上面代码的问题是我在 for each 循环中执行非常昂贵的更新每个 id 的操作(可用:false)并且在每次更改后查询使它无效,而不是在所有更新后。

问题是:考虑到 json-server 的限制,有没有更好的方法来做到这一点?任何批量更新而不是分别向每个 ID 发送请求?也许逻辑上有一些变化?

提前致谢

您当然可以做出一个触发多个请求的突变,并且 returns 结果为 Promise.allPromise.allSettled。类似于:

useMutation((seats) => {
  return Promise.allSettled(seats.map((seat) => axios.patch(...))
})

那么,所有查询将有一个“生命周期”(加载/错误/成功),并且onSuccess只会被调用一次。

我看到的另一个陷阱是您确实希望 hall 字符串成为查询键的一部分:

- useQuery(["hall"], () =>
+ useQuery(["hall", hall], () =>