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

React Hooks:useCallback中变量/状态声明顺序差异(ES5编译)

关于useCallback中变量/函数声明顺序对其行为影响的疑问

说明:代码会经过Babel编译转换为ES5,所有const和let声明都会被转为var。

场景1

function App() {
  const [counter, setCounter] = useState(0);

  const increment = useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  const decrement = useCallback(() => {
    setCounter(counter - 1);
  }, [counter]);

  // 疑问代码段开始
  const incrementOtherCounter = useCallback(() => {
    console.log("runner value :", runner());
    console.log("this is otherCounter:", otherCounter);
    setOtherCounter(otherCounter + 1);
  }, [otherCounter, runner]);

  const [otherCounter, setOtherCounter] = useState(0);

  const runner = () => {
    return "Something ran! :" + counter;
  };
  // 疑问代码段结束

  return (
    <div className="App">
      <button onClick={decrement}>Decrement</button>
      {` ${counter} `}
      <button onClick={increment}>Increment</button>
      <button onClick={incrementOtherCounter}>incrementOtherCounter</button>
    </div>
  );
}

调用incrementOtherCounter()时,输出固定为:

runner value :Something ran! :0
this is otherCounter: 0

无论更新counter状态还是重复调用incrementOtherCounter(),counter和otherCounter始终显示为0,不会变化。

场景2

function App() {
  const [counter, setCounter] = useState(0);

  const increment = useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  const decrement = useCallback(() => {
    setCounter(counter - 1);
  }, [counter]);

  // 疑问代码段开始
  const [otherCounter, setOtherCounter] = useState(0);

  const incrementOtherCounter = useCallback(() => {
    console.log("runner value :", runner());
    console.log("this is otherCounter:", otherCounter);
    setOtherCounter(otherCounter + 1);
  }, [otherCounter, runner]);

  const runner = () => {
    return "Something ran! :" + counter;
  };
  // 疑问代码段结束

  return (
    <div className="App">
      <button onClick={decrement}>Decrement</button>
      {` ${counter} `}
      <button onClick={increment}>Increment</button>
      <button onClick={incrementOtherCounter}>incrementOtherCounter</button>
    </div>
  );
}

调用incrementOtherCounter()能获取到otherCounter的正确值,但runner()返回的counter总是滞后一个更新周期——比如更新counter后,runner()显示的是更新前的值。

场景2运行结果:
场景2运行结果

场景3

function App() {
  const [counter, setCounter] = useState(0);

  const increment = useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  const decrement = useCallback(() => {
    setCounter(counter - 1);
  }, [counter]);

  // 疑问代码段开始
  const runner = () => {
    return "Something ran! :" + counter;
  };

  const incrementOtherCounter = useCallback(() => {
    console.log("runner value :", runner());
    console.log("this is otherCounter:", otherCounter);
    setOtherCounter(otherCounter + 1);
  }, [otherCounter, runner]);

  const [otherCounter, setOtherCounter] = useState(0);
  // 疑问代码段结束

  return (
    <div className="App">
      <button onClick={decrement}>Decrement</button>
      {` ${counter} `}
      <button onClick={increment}>Increment</button>
      <button onClick={incrementOtherCounter}>incrementOtherCounter</button>
    </div>
  );
}

此场景中,counter和otherCounter的值都能正确更新,runner()也能实时返回最新的counter值。

场景3运行结果:
场景3运行结果

核心疑问

我无法理解场景2和场景3的运行逻辑:为什么场景3中incrementOtherCounter()能获取到counter和otherCounter的正确值,而场景2中counter会滞后一个更新周期?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 01:41:09