React中addEventListener内使用useState修改状态不生效如何解决?
React右键点击修改state不生效问题解决方案
问题原因
- 依赖与判断逻辑错误:
testRef是 React 生成的稳定 ref 对象,本身不会随渲染变化,原有代码判断!testRef永远为假,实际应该判断!testRef.current才是检测DOM是否挂载完成。 - 闭包陷阱:原有事件绑定逻辑仅在组件首次挂载时执行一次,捕获的
testState永远是初始值0,所以即使触发更新也只会把值设为1,之后再触发不会产生新的状态变化,自然不会触发监听testState的useEffect打印日志。 - 缺少事件清理逻辑:绑定的右键事件没有在组件卸载时移除,会造成内存泄漏。
- 未阻止右键默认行为:原生
contextmenu事件默认会弹出浏览器右键菜单,可根据需求阻止默认行为。
修复方案
修改后的完整代码如下:
import { useState, useRef, useEffect } from "react"; function Main() { const [testState, setTestState] = useState(0); const testRef = useRef(null); useEffect(() => { // 正确判断DOM是否挂载完成 if (!testRef.current) return; const el = testRef.current; const clickHandler = (event) => { // 阻止默认右键菜单弹出,不需要可以删除该行 event.preventDefault(); // 使用函数式更新规避闭包问题,不需要依赖当前作用域的testState setTestState(prev => prev + 1); } el.addEventListener('contextmenu', clickHandler); // 组件卸载/依赖变化时清理事件,避免内存泄漏 return () => { el.removeEventListener('contextmenu', clickHandler); }; // 该副作用无外部依赖,依赖数组为空即可 }, []); useEffect(() => { console.log('testState: ', testState); }, [testState]); return ( <div ref={testRef} style={{width: '100%', display: 'block', height: '32px', backgroundColor: 'red'}} /> ); } export default Main;
内容的提问来源于stack exchange,提问作者Minseo Lee
相关产品推荐
相关产品推荐

