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

为何react-query的useMutation条件校验失效,频繁点击会触发非法更新请求?

问题原因
  1. mutation.isLoading 状态更新是非同步的:第一次调用 mutation.mutate() 后,React 状态更新需要等待下一次渲染周期,连续快速点击时,前几次点击触发时 isLoading 还未更新为 true,会绕过你的加载状态校验,多次提交变更请求。
  2. 你使用了 Firestore 的 increment() 增量操作,这个逻辑是在服务端执行的,本地缓存的 workoutplan.currentDay 要等 invalidateQueries 触发重新拉取后才会更新,快速点击时多次请求用的都是同一个旧的 currentDay 值做判断,会认为 currentDay>0 始终成立,导致多次提交 -1 的增量请求,最终结果就是 currentDay 变成负数。
解决方案
  • 最简单的方案是直接给切换按钮加禁用状态,在请求过程中、或者当前已经是第一天时禁止点击:
    按钮组件上添加属性 disabled={mutation.isLoading || workoutplan?.currentDay <= 0},从交互层面杜绝连续重复提交的可能。
  • 把非幂等的 increment 操作换成直接传入计算好的确定值,保证重复提交也不会出现异常结果:
    点击时先本地计算合法的新值,直接传给服务端,示例代码:
    const moveDayBack = () => {
      if (workoutplan && !mutation.isLoading) {
        const newCurrentDay = Math.max(0, workoutplan.currentDay - 1);
        if (newCurrentDay !== workoutplan.currentDay) {
          mutation.mutate({
            currentDay: newCurrentDay
          });
        }
      }
    };
    
    这样就算因为状态更新延迟导致多次提交,每次传入的 newCurrentDay 都是0,不会出现负数。
  • 加乐观更新逻辑,点击后立即修改本地缓存的 currentDay 值,后续点击判断用的是更新后的值,从逻辑层面避免错误判断:
    在 useMutation 配置中添加 onMutate 钩子,提前更新缓存,示例代码:
    const mutation = useFirestoreDocumentMutation(
      ref,
      { merge: true },
      {
        onMutate: async (newData) => {
          await queryClient.cancelQueries([...]); // 取消正在进行的拉取请求,避免覆盖本地更新
          const previousData = queryClient.getQueryData([...]);
          // 乐观更新本地缓存
          queryClient.setQueryData([...], (old) => {
            if (!old) return old;
            return {
              ...old,
              data: () => ({
                ...old.data(),
                currentDay: Math.max(0, old.data().currentDay -1)
              })
            };
          });
          return { previousData };
        },
        onError: (err, newData, context) => {
          // 请求失败时回滚到之前的状态
          queryClient.setQueryData([...], context.previousData);
        },
        onSuccess() {
          queryClient.invalidateQueries([...]);
        },
      }
    );
    
  • 后端兜底,给 Firestore 对应集合添加安全规则,限制 currentDay 的值必须 >=0 且 < days 数组的长度,就算前端校验被绕过,非法请求也会被服务端直接拒绝,不会写入异常数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 15:54:03