如何移除React中的事件监听器



我有一个代码,应该在父组件上添加事件侦听器,当元素被单击并在鼠标向上时删除它,但事件侦听器的删除不工作。

const move = (e)=>{
setPosition({top:e.clientY-50,left:e.clientX-65})
}
const handleMouseDown = (e) =>{
backgroundRef.current.addEventListener('mousemove',(e)=>move(e))
}
const handleMouseUp = (e) =>{
backgroundRef.current.removeEventListener('mousemove',(e)=>move(e))
}
return <div ref={iconRef} onMouseDown={handleMouseDown} onMouseUp={handleMouseUp} style={position} className='icon-container' >
<img draggable='false' src={image} alt=''/>
<p>{text}</p>
</div>

您需要将相同的函数引用传递给addEventListener和removeEventListener。您当前在每次调用中传递一个新的匿名函数。

const move = (e)=>{
setPosition({top:e.clientY-50,left:e.clientX-65})
}
const handleMouseDown = (e) =>{
backgroundRef.current.addEventListener('mousemove',move) // passing the same reference 
}
const handleMouseUp = (e) =>{
backgroundRef.current.removeEventListener('mousemove',move) // passing the same reference 
}

我认为对于removeEventListener在这种情况下工作,除了为它传递相等的引用move外,这些函数还可能需要由useCallback保存。因为当状态position改变并且组件重新呈现时,handleMouseUp可以用move的新副本重新创建。

引用等于moveuseCallback的例子:

const Child = ({ image, text, backgroundRef }) => {
const [position, setPosition] = React.useState(null);
const move = React.useCallback((e) => {
setPosition({
top: `${e.clientY - 50}px`,
left: `${e.clientX - 65}px`,
});
}, []);
const handleMouseDown = React.useCallback(() => {
backgroundRef.current.addEventListener('mousemove', move);
}, [move]);
const handleMouseUp = React.useCallback(() => {
backgroundRef.current.removeEventListener('mousemove', move);
}, [move]);
return (
<div
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
style={position}
className="icon-container"
>
<img draggable="false" src={image} alt="" />
<p>{text}</p>
</div>
);
};
const Parent = () => {
const backgroundRef = React.useRef(null);
return (
<section ref={backgroundRef}>
<Child
text="👉 Drag this"
image="https://picsum.photos/100"
backgroundRef={backgroundRef}
/>
</section>
);
};

const App = () => {
return (
<div>
<Parent />
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
section {
position: relative;
width: 200px;
height: 200px;
background-color: pink;
display: flex;
justify-content: center;
align-items: center;
}
.icon-container {
position: absolute;
background-color: lightgreen;
cursor: pointer;
}
.icon-container > * {
pointer-events: none;
user-select: none;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

,或者,如果目标是让组件跟随鼠标移动,则可能不需要从父类宿主事件。组件可以保持active状态,以便通过单击来切换,从而控制拖动是否处于活动状态。

useCallback,addEventListener,和一个ref可以通过这个可选的方法被省略。

active状态的示例:

const Child = ({ image, text }) => {
const [active, setActive] = React.useState(false);
const [position, setPosition] = React.useState(null);
const move = (e) => {
if (!active) return;
setPosition({
top: `${e.clientY - 50}px`,
left: `${e.clientX - 65}px`,
});
};
return (
<div
onMouseDown={() => setActive(true)}
onMouseUp={() => setActive(false)}
style={position}
className="icon-container"
onMouseMove={active ? move : null}
>
<img draggable="false" src={image} alt="" />
<p>{text}</p>
</div>
);
};
const Parent = () => {
return (
<section>
<Child text="👉 Drag this" image="https://picsum.photos/100" />
</section>
);
};
const App = () => {
return (
<div>
<Parent />
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
section {
position: relative;
width: 200px;
height: 200px;
background-color: lightblue;
display: flex;
justify-content: center;
align-items: center;
}
.icon-container {
position: absolute;
background-color: pink;
cursor: pointer;
}
.icon-container > * {
pointer-events: none;
user-select: none;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

相关内容

  • 没有找到相关文章

最新更新