按下Enter键后idNumber变为undefined,报Cannot read property 'length' of undefined问题
问题根本原因
这是典型的React闭包陷阱问题,触发原因如下:
- 你给
useEffect设置了空依赖数组[],意味着这个副作用仅在组件首次渲染时执行一次 - 首次渲染时注册的
keyup事件绑定的是首次渲染时的enterPressed函数,这个函数捕获的idNumber是首次渲染时的初始值undefined - 后续组件重新渲染生成的新
enterPressed函数永远不会被绑定到事件上,所以按下回车时读取的始终是最初的undefined值 - 而
checkID函数没有被旧闭包捕获,每次组件渲染都会生成新的checkID实例,绑定到按钮上的永远是最新的函数,所以能读取到当前最新的idNumber值
解决方案
方案1:优先推荐,改用React内置事件绑定,避免手动操作DOM
直接给input标签加onKeyUp属性,不需要手动用addEventListener绑定,同时删掉原来手动绑定事件的useEffect即可:
<input value={idNumber} id='idNum' onChange={(event) => onChangeHandler(event)} onKeyUp={enterPressed} />
方案2:如果必须手动绑定事件,补全useEffect依赖并添加清理逻辑
useEffect(() => { const submit = document.getElementById('idNum'); const enterPressed = (event) => { if (event.key === 'Enter') { console.log('idNumber.length ' + idNumber.length); } }; submit.addEventListener('keyup', enterPressed); // 组件卸载/依赖变化时清理旧的事件监听 return () => submit.removeEventListener('keyup', enterPressed); }, [idNumber]); // 把idNumber加入依赖数组,state变化时重新绑定最新的事件函数
方案3:用useRef存储state的最新值绕开闭包问题
如果你不想频繁重新绑定事件,可以用ref同步存储最新的idNumber:
const [idNumber, setNumber] = useState(); // 新增ref存储最新值 const idNumberRef = useRef(idNumber); // state变化时同步更新ref useEffect(() => { idNumberRef.current = idNumber; }, [idNumber]); const enterPressed = (event) => { if (event.key === 'Enter') { // 读取ref的current属性拿到最新值 console.log('idNumber.length ' + idNumberRef.current.length); } };
内容的提问来源于stack exchange,提问作者ExtraSun
相关产品推荐
相关产品推荐

