React document.removeEventListener 不起作用

Posted

技术标签:

【中文标题】React document.removeEventListener 不起作用【英文标题】:React document.removeEventListener is not working 【发布时间】:2020-09-19 19:16:23 【问题描述】:

我正在尝试制作一个可拖动的 React 组件,并且代码总是设法到达“删除侦听器”块,但之后组件继续粘在我的鼠标上,所以我肯定搞砸了删除侦听器的步骤,虽然我不确定如何 - 我传递给 document.add/removeEventListener 的两个函数肯定是相同的吗?

useEffect(() => 
            if (dragging && !prevDragging) 
                document.addEventListener("mousemove", onMouseMove)
                document.addEventListener("mouseup", onMouseUp)
             else if (!dragging && prevDragging) 
                console.log('removing listeners')
                document.removeEventListener("mousemove", onMouseMove)
                document.removeEventListener("mouseup", onMouseUp)
                
            
        )

 const onMouseMove = (e) => 
            if (!dragging) return;
            setPos(
                x: e.pageX - rel.x,
                y: e.pageY - rel.y
            );
        e.stopPropagation();
        e.preventDefault();
    

const onMouseUp = (e) => 
        setDragging(false);
        e.stopPropagation();
        e.preventDefault();
    

【问题讨论】:

【参考方案1】:

在每次渲染 React 组件时,都会创建一个新函数。因此,如果您在浏览器的developer tools 中检查event listeners,您会看到在每次渲染后添加了其中的几个。因此,即使您删除了最新的事件监听器,旧的仍然存在。

所以本质上我要说的是函数:-

const onMouseMove = (e) => 
            if (!dragging) return;
            setPos(
                x: e.pageX - rel.x,
                y: e.pageY - rel.y
            );
        e.stopPropagation();
        e.preventDefault();
    

第一次渲染不一样

const onMouseMove = (e) => 
            if (!dragging) return;
            setPos(
                x: e.pageX - rel.x,
                y: e.pageY - rel.y
            );
        e.stopPropagation();
        e.preventDefault();
    

第二次渲染等等。它们在逻辑上是等价的,但不是指同一个函数。

【讨论】:

所以我定义 useEffect 的方式,它应该只在调用 removeEventListener 之前调用一次 addEventListener - 但你说这没关系,因为在组件的每个渲染上,功能都是不同的?那么我如何引用相同的函数呢?谢谢!【参考方案2】:

只需使用 Reacts useCallback 函数,React 就会记住这些函数是相同的。

const onMouseMove = React.useCallback((e) => 
  if (!dragging) return;
  setPos(
    x: e.pageX - rel.x,
    y: e.pageY - rel.y,
  );
  e.stopPropagation();
  e.preventDefault();
, []);

const onMouseUp = React.useCallback((e) => 
  setDragging(false);
  e.stopPropagation();
  e.preventDefault();
, []);

【讨论】:

以上是关于React document.removeEventListener 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

「首席架构师推荐」React生态系统大集合

import * as react from 'react' 与 import react from 'react' 有啥区别

“使用 JSX 时,React 必须在范围内”(react/react-in-jsx-scope 与 index.js 上的“window.React = React”)

React 系列教程

React学习笔记-1-什么是react,react环境搭建以及第一个react实例

react 导入中的 as