【发布时间】:2023-04-02 13:16:02
【问题描述】:
我有一个组件通过addEventListener 和removeEventListener 在多个地方使用事件侦听器。使用 onMouseMove 这样的组件方法是不够的,因为我还需要检测组件之外的事件。
我在组件中使用了钩子,其中有几个在末尾有依赖数组,特别是useCallback(eventFunction, dependencies) 带有要与侦听器一起使用的事件函数。依赖项通常是使用useState 声明的有状态变量。
据我所知,函数的标识在add/remove EventListener 中很重要,因此如果函数在两者之间发生变化,它就不起作用。起初我尝试管理钩子,以便事件函数不会在 add 和 remove 之间更改身份,但由于函数对状态的依赖,这很快变得笨拙。
所以最后我想出了以下模式:由于 setter 函数(useState 的第二个输入参数)获取当前状态作为参数,我可以拥有在第一次渲染后永远不会改变的事件函数(我们仍然称它为挂载吗?)但仍然可以访问最新的状态变量。一个例子:
import React, { useCallback, useEffect, useState } from 'react';
const Component = () => {
const [state, setState] = useState(null);
const handleMouseMove = useCallback(() => {
setState((currentState) => {
// ... do something that involves currentState ...
return currentState;
});
}, []);
useEffect(() => {
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, [/* ... some parameters here ... */]);
// ... more effects etc ...
return <span>test</span>;
};
(这是一个非常简化的插图)。
这似乎工作正常,但我不确定它是否正确 - 使用永远不会改变状态但只是作为访问当前状态的黑客的 setter 函数。
另外,对于需要多个状态变量的事件函数,我必须嵌套 setter 调用。
是否有另一种模式可以更好地处理这种情况?
【问题讨论】:
-
你能不能只在这里使用
state作为那是当前状态。您是否设置状态以触发重新渲染组件的反应? -
如果我这样做,我必须确保
onMouseMove在state更改时更新,即在依赖数组中提供state。然后对removeEventListener的调用将不起作用,因为它不再是相同的效果函数 -
请参阅 render props 作为替代方案。
-
有些事情并没有完全加起来,
onMouseMove应该只依赖于鼠标在事件侦听器附加到的任何元素中移动,这里是窗口。这里的目标是什么? -
目标是一个允许拖拽选择子组件的组件,并且也只根据滚动渲染后者的一个窗口。
onMouseMove取决于对子组件的引用列表(用于检查它们的位置,使用getBoundingClientRect)
标签: javascript reactjs addeventlistener react-hooks usecallback