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

为何useMutation的onSuccess回调输出陈旧的count状态值?

为什么代码输出是0而非666?

这是典型的闭包陷阱导致的问题,具体原因如下:

  • 当你点击按钮调用mutate()时,当前执行的onSuccess回调是组件初始渲染(此时count=0)时创建的,它捕获了这个时刻的count变量。
  • 2秒后setCount(666)触发组件重新渲染,虽然会生成新的useMutation实例和新的onSuccess回调,但已经发起的那个mutation绑定的还是旧的onSuccess,它只会访问闭包里保存的旧值0。
  • 你给useMutation传入的[count]作为键,确实会在count变化时重建mutation实例,但这只影响之后调用的mutate方法,而点击按钮时调用的mutate是count=0时的版本,已经发起的mutation不会受新实例影响。

解决方案:用useRef获取最新状态

useRef的current属性是可变的,不会受组件重新渲染的影响,能始终保存最新的count值:

import "./styles.css";
import { useMutation } from "react-query";
import { useState, useRef, useEffect } from "react";

export default function App() {
  const [count, setCount] = useState(0);
  const countRef = useRef(count);

  // 每次count更新时同步到ref
  useEffect(() => {
    countRef.current = count;
  }, [count]);

  const { mutate } = useMutation(
    () => {
      return new Promise((resolve) => {
        setTimeout(() => resolve("data"), 5000);
      });
    },
    {
      onSuccess: () => {
        console.log(countRef.current); // 此时会输出666
      }
    }
  );

  return (
    <div className="App">
      <button
        onClick={() => {
          mutate();
          setTimeout(() => {
            setCount(666);
          }, 2000);
        }}
      >
        Button
      </button>
    </div>
  );
}

补充说明

如果你尝试把count作为mutation的参数传入,只能拿到调用mutate时的旧值,无法获取之后更新的最新值,所以这种方式不适合你的场景。而useRef是最直接的解决闭包捕获旧值问题的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:25:23