首页 > 解决方案 > 如何使用 React useEffect 窗口 removeEventListener

问题描述

在 React Hooks 文档中,展示了如何在组件的清理阶段移除事件监听器。https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect

在我的用例中,我试图以功能组件的状态属性为条件删除EventListener。

这是一个永远不会卸载组件但应删除事件侦听器的示例:

function App () {
  const [collapsed, setCollapsed] = React.useState(true);

  React.useEffect(
    () => {
      if (collapsed) {
        window.removeEventListener('keyup', handleKeyUp); // Not the same "handleKeyUp" :(
      } else {
        window.addEventListener('keyup', handleKeyUp);
      }
    },
    [collapsed]
  );

  function handleKeyUp(event) {
    console.log(event.key);
    switch (event.key) {
      case 'Escape':
        setCollapsed(true);
        break;
    }
  }

  return collapsed ? (
    <a href="javascript:;" onClick={()=>setCollapsed(false)}>Search</a>
  ) : (
    <span>
      <input placeholder="Search" autoFocus />&nbsp;
      <a href="javascript:;">This</a>&nbsp;
      <a href="javascript:;">That</a>&nbsp;
      <input placeholder="Refinement" />
    </span>
  );
}
ReactDOM.render(<App />, document.body.appendChild(document.createElement('div')));

https://codepen.io/caqu/pen/xBeBMN上的实时示例)

我看到的问题是每次组件渲染时handleKeyUp内部的引用都会发生变化。removeEventListener该函数handleKeyUp需要引用,setCollapsed因此必须用 . 括起来App。搬进去handleKeyUp似乎useEffect也多次开火,失去了对原作的参考handleKeyUp

如何在不卸载组件的情况下有条件地使用 React Hooks window.removeEventListener?

标签: reactjsreact-hooksremoveeventlistener

解决方案


您可以将handleKeyUp函数放在给定的函数内部useEffect根据官方文档,这是推荐的做法collapsed),并且仅在为 false时添加侦听器并返回清理函数。

useEffect(() => {
  if (collapsed) {
    return;
  }

  function handleKeyUp(event) {
    switch (event.key) {
      case "Escape":
        setCollapsed(true);
        break;
    }
  }

  window.addEventListener("keyup", handleKeyUp);
  return () => window.removeEventListener("keyup", handleKeyUp);
}, [collapsed]);

推荐阅读