为何useEffect首次点击计数翻倍?同变量显示数值不一致
React useEffect Hook 问题解答
示例代码
import React, { useState, useEffect } from "react"; const ObjectDependencyExample = () => { const [userData, setUserData] = useState({ name: "John", age: 25 }); const [effectRunCount, setEffectRunCount] = useState(0); useEffect(() => { document.getElementById( "alert" ).innerHTML = `Effect ran ${effectRunCount} times`; console.log("Effect ran due to object dependency change"); setEffectRunCount((prevCount) => prevCount + 1); }, [userData]); const handleUpdateAge = () => { setUserData((prevData) => ({ ...prevData, age: prevData.age + 1 })); }; return ( <div> <h2>User Data</h2> <p>Name: {userData.name}</p> <p>Age: {userData.age}</p> <button onClick={handleUpdateAge}>Update Age</button> <div> <p id="alert"></p> <p>Effect Run Count: {effectRunCount}</p> </div> </div> ); }; export default ObjectDependencyExample;
问题解答
1. 为何页面中使用同一变量effectRunCount的两处内容显示不同数值?
这是React闭包特性和渲染机制共同作用的结果:
useEffect的回调函数会捕获当前渲染周期的状态值,它里面用到的effectRunCount是该次渲染时的快照值;而JSX中直接渲染的{effectRunCount}始终展示最新的状态值。- 比如初始渲染时,
useEffect执行,用当时的effectRunCount=0更新#alert,随后更新状态到1触发重新渲染。这次重新渲染时userData没变化,useEffect不执行,所以#alert停留在0,而JSX已经显示最新的1。后续每次点击按钮,useEffect执行时用的都是上一次渲染的effectRunCount值,和JSX的最新值始终差1,因此两处显示不同。
2. 为何首次点击按钮后,#alert元素的innerHTML会从0变为2?
核心原因是React开发环境的Strict Mode特性,加上状态更新的连锁触发:
- 首次点击按钮后,
userData生成新对象(引用改变),触发组件重新渲染,此时effectRunCount=1,useEffect执行:先把#alert设为Effect ran 1 times,再更新状态到2,触发再次渲染。 - 在开发环境的Strict Mode下,React会对
useEffect执行两次(用于检测副作用是否可安全清理),第二次执行useEffect时,捕获到的effectRunCount=2,于是把#alert更新为Effect ran 2 times,同时将状态更新到3。 - 最终你看到
#alert从初始的0变为2,这是Strict Mode下useEffect重复执行导致的。
内容的提问来源于stack exchange,提问作者Fuaad
相关产品推荐
相关产品推荐

