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就会一直访问旧的数组引用,这才是你之前预想的“拿到旧值”的情况。
总结你的理解误区
- 混淆了值类型和引用类型的闭包捕获逻辑:值类型(比如数字、字符串)捕获的是当前值,引用类型捕获的是内存地址,只要地址不变,访问的就是最新内容。
- 把全局变量和React组件状态混为一谈:全局变量不受React渲染周期约束,修改后直接生效;而组件状态是通过
setState更新,且会生成新的引用(对于引用类型),才会触发依赖更新。
内容的提问来源于stack exchange,提问作者Sarthak Sharma
相关产品推荐
相关产品推荐

