如何使用 React useEffect 窗口 removeEventListener [英] How do I window removeEventListener using React useEffect

查看:33
本文介绍了如何使用 React useEffect 窗口 removeEventListener的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In React Hooks documents it is shown how to removeEventListener during the component's cleanup phase. https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect

在我的用例中,我试图以功能组件的状态属性为条件删除事件监听器.

In my use case, I am trying to removeEventListener conditional to a state property of the functional component.

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

Here's an example where the component is never unmounted but the event listener should be removed:

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 上的实时示例)

我看到的问题是 removeEventListener 中的 handleKeyUp 引用在每次渲染组件时都会发生变化.函数handleKeyUp 需要对setCollapsed 的引用,因此它必须被App 括起来.在 useEffect 中移动 handleKeyUp 似乎也触发多次并丢失对原始 handleKeyUp 的引用.

The problem I see is that the handleKeyUp reference inside removeEventListener is changing every time the component renders. The function handleKeyUp needs a reference to setCollapsed so it must be enclosed by App. Moving handleKeyUp inside useEffect also seems to fire multiple times and lose the reference to the original handleKeyUp.

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

How can I conditionally window.removeEventListener using React Hooks without unmounting the component?

推荐答案

您可以将 handleKeyUp 函数放在赋予 useEffect (这是推荐的方式根据官方文档进行操作),并且仅在 collapsed 为 false 时添加侦听器并返回清理函数.

You can put the handleKeyUp function inside of the function given to useEffect (which is the recommended way of doing it according to the official documentation) and only add the listener and return a cleanup function when collapsed is 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]);

这篇关于如何使用 React useEffect 窗口 removeEventListener的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆