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

React中useCallback为何能获取更新后的全局变量?

React useCallback 与全局变量的闭包误区解析

先看你提供的组件代码:

import React, {useEffect, useCallback, useState} from 'react';

let myHistory = [];

export function App(props) {

  const [toggle, setToggle] = useState(false); // 用来触发重渲染
 
  const func = useCallback(() => {
    console.log(myHistory);
  }, [myHistory]);

  func();

  useEffect(() => {
     console.log("UseEffect Executed")
  }, [myHistory]);

  return (
    <div className='App'>
      <button onClick={() => {
        setToggle(!toggle)
        myHistory.push(1);
      }}>Add to history</button>
    </div>
  );
}

核心原因:闭包捕获的是引用,不是快照值

你之前的误区在于,以为闭包会捕获变量的“固定值”,但对于数组、对象这类引用类型,闭包捕获的是它们在内存中的引用地址,而不是当时的内容快照。

全局变量myHistory是一个数组,它的引用从始至终都没变过——你只是用push修改了数组内部的元素,并没有替换整个数组(比如改成myHistory = [1])。所以不管func是第一次创建的还是复用的,它里面访问的myHistory都是同一个内存地址的数组,每次执行func()时,都会直接读取这个数组的最新内容。

useCallback的作用边界

useCallback的依赖数组是用来决定是否重新生成函数的:只有当依赖项的引用发生变化时,它才会返回一个新的函数。这里myHistory的引用没改,所以func一直是最初创建的那个函数,但这并不影响它访问全局变量的最新状态——因为全局变量不在React的状态管理体系里,它的修改是直接作用于内存的,和组件渲染周期无关。

对比组件状态的情况

如果把myHistory改成用useState声明的组件状态:

const [myHistory, setMyHistory] = useState([]);
// 点击按钮时更新状态
setMyHistory(prev => [...prev, 1]);

这时候每次更新都会生成一个新的数组引用,useCallback的依赖myHistory变了,就会重新创建func,闭包也会捕获新的数组引用。如果没更新依赖,那func就会一直访问旧的数组引用,这才是你之前预想的“拿到旧值”的情况。

总结你的理解误区

  1. 混淆了值类型和引用类型的闭包捕获逻辑:值类型(比如数字、字符串)捕获的是当前值,引用类型捕获的是内存地址,只要地址不变,访问的就是最新内容。
  2. 把全局变量和React组件状态混为一谈:全局变量不受React渲染周期约束,修改后直接生效;而组件状态是通过setState更新,且会生成新的引用(对于引用类型),才会触发依赖更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:13:16