避免在 React 中状态更改时添加无休止的事件侦听器

问题描述 投票:0回答:1

我有一个状态变量

items
,它只是具有 ID 和
ref
(指向 HTMLDivElement)的项目的集合(对象),还有一个状态变量
attachments
,它是另一个集合,但具有如果某个项目被拖动到靠近它的位置,我将更改
opacity
键。

简而言之,当

item.ref
mousemove
接近
attachment
时,将
attachment
opacity
键更新为
1
(从
0
)。这是我如何实现这一目标的代码:

const items = getFromStore('items');
const attachments = getFromStore('attachments');

useEffect(() => {
  for(const id in items) {
    const element = items[id].ref;
    element.addEventListener('mousedown', (e) => handleMouseDown(e, element);
  }
}, [items, attachments]);

handleMouseDown
功能:

const handleMouseDown = useCallback((e, element) => {
  ..
  ..
  const mouseMove = (e) => {
    ..
    ..
    updateAttachment(id, { opacity: 1 })
  };

  window.addEventListener('mousemove', mouseMove);
}, [attachments] /* notice the dependency */);

当我们移动/拖动项目时,会发生对

updateAttachment
的调用。这里的问题是,因为我的
useEffect
也依赖于
attachments
,所以它能够重建事件监听器函数,现在每次用户移动鼠标时,我都会得到数千个事件监听器,因为
handleMouseDown
函数更新
attachments
,然后,因为
attachments
已经更新,所以再次运行效果,依此类推。

我做错了什么?

reactjs mouseevent addeventlistener react-state-management
1个回答
0
投票

您需要从效果中返回一个清理函数,以便在效果重新运行时取消订阅事件:

useEffect(() => {
  const listeners = {};
  for (const id in items) {
    const element = items[id].ref;
    listeners[id] = (e) => handleMouseDown(e, element)
    element.addEventListener('mousedown', listeners[id]);
  }

  return () => {
    for (const id in items) {
      const element = items[id].ref;
      element.removeEventListener('mousedown', listeners[id]);
    }
  }
}, [items, attachments]);
© www.soinside.com 2019 - 2024. All rights reserved.