useEffect如何形成闭包?为何模拟代码结果不同?
为什么React的useEffect能捕获初始值,而你的模拟代码不行?
核心差异在于变量的作用域和React的渲染机制:
1. React代码中的变量逻辑
在你的React示例里:
count是组件函数App每次渲染时的局部变量。当你点击按钮调用setCount时,React会重新执行App函数,生成一个全新的count变量(值为更新后的数字),但这个新变量和之前渲染时的count是完全独立的两个变量。- 你的
useEffect依赖数组是[],意味着这个回调只会在第一次渲染时被创建并执行一次。它捕获的是第一次渲染时的那个count(值为0),后续的重新渲染不会修改这个已经存在的闭包,所以无论你点击多少次,最终alert的都是第一次捕获的0。
2. 你的模拟代码中的变量逻辑
而你的模拟代码里:
count是全局变量,整个代码生命周期里只有这一个count。当setTimeout(() => count=6, 100)执行后,这个全局变量的值被修改。1秒后定时器触发时,读取的就是这个已经被修改的全局变量的值,所以输出6。
模拟React的行为(供参考)
如果要让你的模拟代码和React表现一致,需要模拟React的渲染机制——每次"渲染"创建独立的局部变量,而不是用全局变量:
// 模拟React组件的渲染:每次渲染执行一次该函数 function AppRender() { let count = 0; // 每次渲染的局部变量,和其他渲染的count独立 // 模拟useEffect,依赖为空时仅执行第一次渲染的回调 function useEffect(callback) { callback(); } useEffect(() => { function longResolve() { setTimeout(() => console.log(count), 1000); } longResolve(); }); // 模拟setCount触发重新渲染 setTimeout(() => { AppRender(); // 重新渲染生成新的count,但不影响之前的回调 }, 100); } AppRender();
这段代码执行后会输出0,和React的表现一致——第一次渲染的回调捕获的是自己那一次的局部count,后续重新渲染的新count和它无关。
内容的提问来源于stack exchange,提问作者d11
相关产品推荐
相关产品推荐

