You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Query结合json-server如何实现单请求批量PATCH多ID资源

解决方案

先明确json-server的原生能力边界

原生开箱即用的json-server不支持单请求批量更新多条资源,它默认遵循标准REST路由设计,单条资源更新只能走PATCH /{资源名}/{资源id}的路径,没有内置批量操作的路由。但可以通过两种路径优化现有实现,完全解决你提到的性能和重复触发缓存失效的问题。


方案1:不改动json-server,纯前端逻辑优化

这个方案不需要改后端服务,调整现有前端代码就能解决90%的问题:

  • 统一等待所有更新请求完成后再触发缓存失效
    你现在的核心问题是把缓存失效逻辑写在了单个useTakeSeat的onSuccess回调里,每完成一个座位的更新就会触发一次缓存刷新。只需要把所有更新请求的Promise收集起来,用Promise.all等待所有请求全部成功后,再执行一次缓存失效即可。
    改造后的sendRequest逻辑参考:

    const sendRequest = useCallback(async () => {
      try {
        // 收集所有更新请求的Promise
        const updateTasks = selected.map((item) =>
          takeSeat.mutateAsync({ id: item.id, hall: "hallA" })
        );
        // 等待所有请求完成
        await Promise.all(updateTasks);
        // 所有请求成功后统一刷新一次缓存
        useGetHallLayout.invalidate();
        setSelected([]);
      } catch (err) {
        // 这里加错误提示,比如部分座位预订失败
        console.error("预订失败", err);
      }
    }, [selected, takeSeat]);
    

    记得把useTakeSeat初始化时传入的onSuccess回调删掉,避免重复触发失效。

  • 加乐观更新提升体验
    不需要等接口返回再刷新数据,用户点击预订按钮时直接手动修改React Query的本地缓存,把选中座位的状态改成已预订,后台静默发送更新请求,请求失败时再把缓存回滚即可,用户感知不到请求等待时间。核心实现就是在发请求前调用queryClient.setQueryData直接更新本地缓存:

    // 发请求前先更新本地缓存
    queryClient.setQueryData(["hall", "hallA"], (oldData) => {
      return oldData.map(seat => {
        const isSelected = selected.some(s => s.id === seat.id);
        return isSelected ? {...seat, available: false} : seat
      })
    })
    
  • 修复现有代码的小隐患

    • 你的useGetHallLayout的queryKey目前只写了["hall"],如果后续新增hallB、hallC等多个影厅,不同影厅的缓存会互相覆盖,建议改成["hall", hall],缓存失效时也对应指定queryKey,避免误刷新其他影厅的数据。
    • handleSelect回调里用了函数式状态更新,完全不需要把selected加到useCallback依赖里,去掉后可以避免回调不必要的重创建。

方案2:给json-server加10行代码实现批量更新接口

如果不想前端发送多个并发请求,可以给json-server加一个极简的自定义批量更新路由,改动量非常小:

  1. 新建一个自定义的server入口文件,比如server.js:
    const jsonServer = require('json-server');
    const server = jsonServer.create();
    const router = jsonServer.router('db.json');
    const middlewares = jsonServer.defaults();
    
    server.use(middlewares);
    server.use(jsonServer.bodyParser);
    
    // 自定义批量更新接口
    server.patch('/:hall/batch', (req, res) => {
      const { hall } = req.params;
      const { ids } = req.body; // 接收要更新的座位id数组
      const db = router.db;
      // 批量把对应座位的available改成false
      db.get(hall).forEach(seat => {
        if (ids.includes(seat.id)) {
          seat.available = false;
        }
      }).write();
      // 返回更新后的全量影厅数据
      res.jsonp(db.get(hall).value());
    })
    
    server.use(router);
    server.listen(3000, () => {
      console.log('JSON Server is running on port 3000');
    })
    
  2. 启动服务时不再直接跑json-server --watch db.json,而是跑node server.js。
  3. 前端新增一个批量更新的mutation,预订时只需要发一次请求,把选中的座位id数组传过去即可,请求完成后只需要触发一次缓存失效,性能最优。

内容的提问来源于stack exchange,提问作者Przemo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 02:57:32