繁体   English   中英

React Hooks:如何清理事件监听器?

[英]React Hooks: How to clean event listeners?

我有一个组件Example ,我想在本地 state display更改为false时清除事件侦听器,当show prop 为truedisplay设置为true ,反之亦然。

代码:

const Example = ({ show, onClose }) => {
  const [display, setDisplay] = useState(false);

  const handleClick = (e) => {
    onClose();
    console.log(display);
  };

  useEffect(() => {
    if (display) {
      document.addEventListener('click', handleClick);
    } else {
      document.removeEventListener('click', handleClick);
    }
  }, [display, handleClick]);

  useEffect(() => {
    if (show) {
      setDisplay(show);
    } else {
      setDisplay(false);
    }
  }, [show]);

  return <div>{display && <p>Hi</p>}</div>;
};

问题:

  • 该组件无法清除事件侦听器,因为每次Example呈现时都会生成 function handleClick()新引用
  • 每次调用handleClick()时,它都会记录displaytrue
  • 鼠标点击7-8次后,控制台日志达到7-8K

我在这里做错了什么? 谢谢:)

为了在 useEffect 中进行清理,请在效果中返回 function。 每次效果重新运行和组件卸载时都会调用 function。

这将允许正确删除事件侦听器的原因是因为 useEffect 在当前版本的handleClick function 上创建了一个闭包。 这允许清理 function 具有相同的参考,因此可以正确清理。 它在原始版本中不起作用,因为每次重新运行 useEffect 时,都会关闭新版本的handleClick ,然后尝试使用新版本进行清理。

useEffect(() => {
  if (!display) {
    return;
  }

  document.addEventListener('click', handleClick);

  return () => document.removeEventListener('click', handleClick);
}, [display, handleClick]);

您可以通过使用对handleClick function 的引用来进一步降低效果的发生频率。

例如,这是最基本的。 尽管您可以轻松地将一些参考和额外的使用效果抽象到一个单独的钩子中。

const handleClickRef = useRef(handleClick);

useEffect(()=>{
  handleClickRef.current = handleClick;
},[handleClick])

useEffect(() => {
  if (!display) {
    return;
  }
  const funct = (evt)=>handleClickRef.current(evt);
  document.addEventListener('click',funct);

  return () => document.removeEventListener('click', funct);
}, [display]);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM