我在无状态组件中使用react
挂钩。下面是源代码:
const MyComp = ({focused}) => {
...
const keyPressListener = (e: KeyboardEvent) => {
console.log('key press:', e);
};
useEffect(() => {
if (focused) {
console.log('add event listener');
window.addEventListener('keydown', keyPressListener);
} else {
console.log('remove event listener');
window.removeEventListener('keydown', keyPressListener);
}
}, [focused]);
...
}
它侦听属性focused
。它为true时添加keydown侦听器,为false时将其删除。我可以看到有关add/remove event listener
的控制台日志,但是删除后仍会调用keyPressListener
函数。我看到很多人有同样的问题,因为他们没有绑定功能。但是在这种情况下,我认为不需要箭头功能。
答案 0 :(得分:3)
只要focused
属性值更改,MyComp
就会重新渲染。在每次重新渲染时,都会创建一个新的keyPressListener
函数。通过keypress
钩子可以从useEffect
事件中添加或删除此新功能。
因此,从keypress
事件中删除的内容不是先前添加的 keyPressListener
,而是以前未添加的新创建的函数。
最终结果是原始的keyPressListener
保留添加到keypress
事件中。
您将keyPressListener
移动可以移出MyComp
。与keypress
事件的添加和删除功能将引用相同的功能。
您可以记住keyPressListener
函数,以便可以从keypress
事件中添加和删除相同的函数。由于您使用的是钩子,因此可以继续使用 useMemo 或 useCallback
const MyComp = ({ focused }) => {
const keyPressListener = ({ code }) => {
console.log('key press:', code);
};
const memoizedListener = useMemo(() => keyPressListener, []);
// or use
// const memoizedListener = useCallback(keyPressListener, []);
console.log('rendered again');
useEffect(() => {
if (focused) {
console.log('add event listener');
window.addEventListener('keydown', memoizedListener);
} else {
console.log('remove event listener');
window.removeEventListener('keydown', memoizedListener);
}
}, [focused, memoizedListener]);
return <h1>Test component</h1>;
};
希望这可以帮助您了解上述代码的工作原理。
答案 1 :(得分:0)
在useEffect挂钩中附加EventListener通常需要“清理”。像这样重写您的useEffect
钩子:
useEffect(() => {
if (focused) {
console.log('add event listener');
window.addEventListener('keydown', keyPressListener);
}
return () => {
console.log('remove event listener');
window.removeEventListener('keydown', keyPressListener);
};
}, [focused]);
您还可以使用useRef
钩子来包含要在清除时删除的事件侦听器回调。