`window.removeEventListener('keydown')`在React hooks函数中不起作用

时间:2019-06-04 00:09:06

标签: reactjs

我在无状态组件中使用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函数。我看到很多人有同样的问题,因为他们没有绑定功能。但是在这种情况下,我认为不需要箭头功能。

2 个答案:

答案 0 :(得分:3)

只要focused属性值更改,MyComp就会重新渲染。在每次重新渲染时,都会创建一个新的keyPressListener函数。通过keypress钩子可以从useEffect事件中添加或删除此新功能。

因此,从keypress事件中删除的内容不是先前添加的 keyPressListener,而是以前未添加的新创建的函数。 最终结果是原始的keyPressListener保留添加到keypress事件中。

解决方案1 ​​

您将keyPressListener移动可以移出MyComp。与keypress事件的添加和删除功能将引用相同的功能。

解决方案2

您可以记住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钩子来包含要在清除时删除的事件侦听器回调。