为什么这段React代码中调用setCounter后state没有更新?
问题原因
- 核心原因是闭包陷阱:你给
useEffect传入的依赖数组是空数组[],意味着这个副作用只会在组件首次挂载时执行1次。此时绑定的click事件回调函数,捕获的是组件初始化阶段的counter变量(值为初始值0),后续组件状态更新时,这个回调不会重新创建,永远访问的都是最初的闭包变量,所以打印结果始终是0。 setCounter实际已经生效:你可以在返回的JSX中加入<span>{counter}</span>测试,点击按钮后页面会正常显示counter为1,状态更新是成功的,只是你打印的是闭包中缓存的旧值。- 额外问题:手动调用
addEventListener绑定原生事件没有做卸载清理,会导致内存泄漏,且不符合React的事件处理最佳实践。
修复方案
方案1:使用React合成事件(推荐)
直接用React内置的onClick属性绑定事件,天然可以拿到最新的状态,不需要手动操作DOM:
import { useEffect, useState } from "react"; const Button = () => { const [counter, setCounter] = useState(0) const handleClick = () => { setCounter(1); } // 监听counter变化打印最新值 useEffect(() => { console.log('counter最新值: ', counter) }, [counter]) return ( <button onClick={handleClick}>Click Me</button> ) } export default Button;
方案2:保留原生事件绑定的修复方式
如果必须使用原生事件绑定,需要补充依赖声明和事件清理逻辑:
import { useEffect, useRef, useState } from "react"; const Button = () => { const [counter, setCounter] = useState(0) const btnRef = useRef(); useEffect(() => { const handleClick = () => { setCounter(1); console.log('counter 闭包值: ', counter); } const btn = btnRef.current btn.addEventListener('click', handleClick) // 卸载/依赖更新时清理旧事件 return () => btn.removeEventListener('click', handleClick) }, [counter]) // 把counter加入依赖,状态更新后重新绑定回调拿到最新值 return ( <button ref={btnRef}>Click Me</button> ) } export default Button;
内容的提问来源于stack exchange,提问作者user3760959
相关产品推荐
相关产品推荐

