rpi*_*var 0 addeventlistener mousemove reactjs react-hooks removeeventlistener
我试图在window单击对象时添加一个事件侦听器,然后在再次单击该对象时删除该事件侦听器。
Card单击组件时,状态isCardMoving会打开或关闭。
我添加了一个useEffect来观看isCardMoving。当isCardMoving打开时,它应该向mousemove触发该handleCardMove功能的窗口添加一个事件侦听器。该函数仅记录鼠标的坐标。
如果我再次单击该卡,isCardMoving将为 false,并且我希望窗口上的事件侦听器在useEffect.
isCardMoving但会发生什么情况,事件侦听器将在is时添加true,然后一旦isCardMovingis就不会被删除false。
import React from 'react';
const App = () => {
const [isCardMoving, setIsCardMoving] = React.useState(false);
React.useEffect(() => {
if (isCardMoving) window.addEventListener('mousemove', handleCardMove);
else window.removeEventListener('mousemove', handleCardMove);
}, [isCardMoving]);
const handleCardMove = (event) => console.log({ x: event.offsetX, y: event.offsetY });
return <Card onClick={() => setIsCardMoving(!isCardMoving)} />;
};
Run Code Online (Sandbox Code Playgroud)
然后我尝试ref在窗口上设置 a ,认为由于某种原因我可能需要先前引用该窗口:
import React from 'react';
const App = () => {
const [isCardMoving, setIsCardMoving] = React.useState(false);
const windowRef = React.useRef(window); // add window ref
// update window ref whenever window is updated
React.useEffect(() => {
windowRef.current = window;
}, [window]);
React.useEffect(() => {
// add and remove event listeners on windowRef
if (isCardMoving) windowRef.current.addEventListener('mousemove', handleCardMove);
else windowRef.current.removeEventListener('mousemove', handleCardMove);
}, [isCardMoving]);
const handleCardMove = (event) => console.log({ x: event.offsetX, y: event.offsetY });
return <Card onClick={() => setIsCardMoving(!isCardMoving)} />;
};
Run Code Online (Sandbox Code Playgroud)
这看起来和之前的效果是一样的。
您无法在 React 或其他基于虚拟 DOM 的应用程序中删除这样的事件侦听器。由于虚拟 DOM 库的性质,您必须在卸载生命周期中删除事件侦听器,该事件侦听器位于 React hooks 中并且在其useEffect自身中可用。所以你必须像下面那样使用 return 关键字来执行此操作。它将执行与componentWillUnmount类基组件中相同的操作:
React.useEffect(() => {
if (isCardMoving) window.addEventListener("mousemove", handleCardMove);
return () => window.removeEventListener("mousemove", handleCardMove);
}, [isCardMoving]);
Run Code Online (Sandbox Code Playgroud)
工作演示:
正如 @ZacharyHaber 在评论中所说,这种行为背后的主要原因是您的handleCardMove函数将在每次渲染时重新定义,因此为了克服这种情况,我们需要使用回调在每次渲染时从窗口中解除事件绑定useEffect。您还可以使用该useCallback方法使您的初始代码正常工作。尽管如此,您还需要将前一个useEffect回调添加到组件中,以确保事件侦听器将在组件卸载周期中删除,这需要更多的编码,但是这个回调将与上述方法执行相同的操作。
const handleCardMove = React.useCallback((event) => {
console.log({ x: event.offsetX, y: event.offsetY });
}, []);
React.useEffect(() => {
if (isCardMoving) window.addEventListener("mousemove", handleCardMove);
else window.removeEventListener("mousemove", handleCardMove);
return () => window.removeEventListener("mousemove", handleCardMove);
}, [isCardMoving, handleCardMove]);
Run Code Online (Sandbox Code Playgroud)
工作演示:
| 归档时间: |
|
| 查看次数: |
8286 次 |
| 最近记录: |