我正在尝试在keydown事件上添加一些行为,但是useEffect无法正常工作。
代码如下:
const Test = ({}) => {
const [value, setValue] = React.useState(0);
const add= (sum) => {
setValue(value+sum);
}
React.useEffect(()=> {
const handleKeyDown = (e: KeyboardEvent) => {
console.log("keypress", value);
if (e.key === 'ArrowLeft') {
add(-1);
} else if (e.key === 'ArrowRight') {
add(1);
}
}
document.addEventListener('keydown', event => handleKeyDown(event));
return () => {
console.log("remove event")
document.removeEventListener('keydown', event => handleKeyDown(event));
};
}, [add])
return <span>Count {value}</span>
}
Here is jsfiddle code-您可以在控制台上的按键上看到它多次调用。
如果将空数组放在useEffect依赖项上,则在调用add函数时,该值将始终为0。如果将add或value放在依赖项数组上,则每按一次useEffect键都会触发多次。有解决方案吗?
答案 0 :(得分:2)
通过将内联箭头函数传递给addEventListener
,您每次都创建一个新的处理程序,而删除该处理程序将不起作用,因为再次声明要删除的新函数-该函数从来没有添加过:
// creates a new handler function every time
document.addEventListener('keydown', event => handleKeyDown(event));
// removing a function that isn't currently registered as a
// listener on the document, because it's a brand new inline function.
document.removeEventListener('keydown', event => handleKeyDown(event));
每次渲染时都会添加另一个keydown侦听器实例,并且永远不会删除它们,因此当您与应用交互时,它们会堆积。
无需创建新函数即可仅调用现有函数。尝试以下方法:
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
您的add
函数存在类似问题。将add
声明为效果依赖项会导致效果每次运行,因为add
会在每个渲染器上重新声明。将其包装在useCallback
中,以防止每次都重新创建它:
const add = React.useCallback((sum) => {
setValue(value+sum);
}, [value]);