如何在每次设置key变量时触发useEffect,包括值未变更的场景
const [key, setKey] = useState<string | null>(null); const pointerLocation = useRef(0); useEffect(() => { console.count("key listener"); const handleKeyDown = (e: KeyboardEvent) => { setKey(e.key); }; window.addEventListener("keydown", handleKeyDown); return () => { window.removeEventListener("keydown", handleKeyDown); }; }, [key]); useEffect(() => { const letter = document.getElementsByClassName("letter"); if (key) { if (letter[pointerLocation.current] && key.length === 1) { letter[pointerLocation.current].textContent = key; pointerLocation.current++; } } if (key === "Backspace") { if (letter[pointerLocation.current - 1]) { letter[pointerLocation.current - 1].textContent = ""; pointerLocation.current--; } } }, [key, pointerLocation]);
问题分析
第二个useEffect仅在key状态变更时执行,重复按下同一按键时,key值未发生变化,导致该钩子无法触发,文本无法更新。尝试添加pointerLocation到依赖数组无效,因为useRef的.current变更不会触发组件重渲染;为key添加随机数触发更新则会导致不必要的重渲染。
解决方案
直接将文本更新逻辑整合到键盘事件回调中,同时修复第一个useEffect的依赖问题:
const [key, setKey] = useState<string | null>(null); const pointerLocation = useRef(0); useEffect(() => { console.count("key listener"); const handleKeyDown = (e: KeyboardEvent) => { const pressedKey = e.key; setKey(pressedKey); // 保留状态更新(若其他逻辑需要依赖key状态) const letterElements = document.getElementsByClassName("letter"); if (pressedKey.length === 1) { if (letterElements[pointerLocation.current]) { letterElements[pointerLocation.current].textContent = pressedKey; pointerLocation.current++; } } else if (pressedKey === "Backspace") { if (pointerLocation.current > 0 && letterElements[pointerLocation.current - 1]) { letterElements[pointerLocation.current - 1].textContent = ""; pointerLocation.current--; } } }; window.addEventListener("keydown", handleKeyDown); return () => { window.removeEventListener("keydown", handleKeyDown); }; }, []); // 空数组确保事件仅绑定一次
说明
- 优化事件绑定:第一个
useEffect依赖改为空数组,仅在组件挂载时绑定一次键盘事件,卸载时移除,避免重复绑定造成的性能损耗。 - 直接处理按键逻辑:将文本更新逻辑移到
handleKeyDown回调中,每次按键(包括重复按键)都会立即执行,无需依赖key状态变化触发useEffect。 - 避免无效依赖:移除第二个
useEffect,不再依赖key或pointerLocation,彻底解决重复按键不触发更新的问题。
内容的提问来源于stack exchange,提问作者Matt Yak
相关产品推荐
相关产品推荐

