如何使用React useEffect窗口removeEventListener

问题描述 投票:2回答:1

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

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

下面是一个示例,其中组件永远不会卸载但应删除事件侦听器:

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?

reactjs react-hooks removeeventlistener
1个回答
3
投票

你可以将handleKeyUp函数放在给useEffect给出的函数内部,只有当collapsed为false时才添加监听器并返回一个清理函数。

useEffect(() => {
  if (!collapsed) {
    function handleKeyUp(event) {
      switch (event.key) {
        case "Escape":
          setCollapsed(true);
          break;
      }
    }

    window.addEventListener("keyup", handleKeyUp);
    return () => window.removeEventListener("keyup", handleKeyUp);
  }
}, [collapsed]);
© www.soinside.com 2019 - 2024. All rights reserved.