使用 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.all
或 Promise.allSettled
。类似于:
useMutation((seats) => {
return Promise.allSettled(seats.map((seat) => axios.patch(...))
})
那么,所有查询将有一个“生命周期”(加载/错误/成功),并且onSuccess
只会被调用一次。
我看到的另一个陷阱是您确实希望 hall
字符串成为查询键的一部分:
- useQuery(["hall"], () =>
+ useQuery(["hall", hall], () =>
我有一个非常基本的应用程序原型,可以用来预订座位。用户选择 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.all
或 Promise.allSettled
。类似于:
useMutation((seats) => {
return Promise.allSettled(seats.map((seat) => axios.patch(...))
})
那么,所有查询将有一个“生命周期”(加载/错误/成功),并且onSuccess
只会被调用一次。
我看到的另一个陷阱是您确实希望 hall
字符串成为查询键的一部分:
- useQuery(["hall"], () =>
+ useQuery(["hall", hall], () =>