Javascript React useffect和mousedown侦听器

Javascript React useffect和mousedown侦听器,javascript,reactjs,Javascript,Reactjs,我有一个模式,如果用户在其外部单击,该模式将关闭 接近一号-通过isModalOpened,因此只有当isModalOpened为真时,状态才会在单击时更新 const [isModalOpened, toggleModal] = useState(false); const ref = useRef(null); const clickOut = (e) => { if (!ref.current.contains(e.target) && isModalOpene

我有一个模式,如果用户在其外部单击,该模式将关闭

接近一号-通过
isModalOpened
,因此只有当
isModalOpened
为真时,状态才会在单击时更新

const [isModalOpened, toggleModal] = useState(false);
const ref = useRef(null);

const clickOut = (e) => {
  if (!ref.current.contains(e.target) && isModalOpened) {
     toggleModal(false);
  }
};

React.useEffect(() => {
  window.addEventListener('mousedown', clickOut);

  return () => {
     window.removeEventListener('mousedown', clickOut);
  };
}, [isModalOpened]);
方法二-从dep阵列中删除
ismodaloped

const [isModalOpened, toggleModal] = useState(false);
const ref = useRef(null);

const clickOut = (e) => {
  if (!ref.current.contains(e.target)) {
     toggleModal(false);
  }
};

React.useEffect(() => {
  window.addEventListener('mousedown', clickOut);

  return () => {
     window.removeEventListener('mousedown', clickOut);
  };
}, []);
问题:我应该传递还是不传递
ismodaloped
到dep数组?

您不需要它

原因是,如果将
切换到相同的
false
值,则不会导致重新渲染


因此,您不必担心
ismodalopend
的值会导致函数中不包含变量,这会导致根本不需要依赖关系。

不,您不应该将
isModalOpen
传递到深度数组,因为在这种情况下,您的效果只会删除并再次添加侦听器。这是不必要的

方法每次
ismodaloped
更改时,都会运行钩子,在模式关闭时删除全局侦听器。方法2将在(未)装入组件时运行钩子,这意味着全局侦听器将在整个组件生命周期中处于活动状态

答案取决于您计划如何使用该组件。我猜您计划在模态打开之前安装组件(因此为
false
初始状态),这意味着您的第二种方法将从安装组件到卸载组件的那一刻监听
mousedown
事件。如果您计划仅在打开模式时安装组件,则此方法将有效。但您没有,这意味着您应该仅在打开模式时设置全局侦听器

第一种方法是正确的

*编辑


但是您可以删除if语句中的
ismodalopend
检查。

我建议对此采取一种不同的方法。在这里,我将
clickOut
函数包装在
useCallback
中,它的依赖项为
toggleModal
ref
,而
clickOut
的依赖项为
useffect
。这样,每当
ref
toggleModal
更改时,您就有了一个新的
clickOut
参考,如果您有了新的
clickOut
参考,您的侦听器将在
useffect
中重新分配。这将有助于您在每次渲染时取消不必要的
单击
函数创建,并优化渲染

因此,根据我的建议,您的代码将如下所示:

const [isModalOpened, toggleModal] = useState(false);
const ref = useRef(null);

const clickOut = useCallback((e) => {
  if (!ref.current.contains(e.target) && isModalOpened) {
     toggleModal(false);
  }
}, [isModalOpened, ref]);

React.useEffect(() => {
  window.addEventListener('mousedown', clickOut);

  return () => {
     window.removeEventListener('mousedown', clickOut);
  };
}, [clickOut]);

如果创建对话框,请不要使用窗口,而是放置一个全屏固定透明div或半透明div,并将事件附加到此对话框。为什么?因为它允许你在对话中有对话…嗯,很有趣。因此,有两个答案是为了删除依赖项,而您的答案是为了保留依赖项。这两个答案是关于
ismodalopend
检查您的if语句,但是我的答案是正确的。您可以通过在浏览器的开发工具中检查全局侦听器来检查这一点(或者更简单地说,通过使用console.log并在调用
clickOut
函数时进行检查)。我喜欢,这似乎是最好的解决方案。我希望在react方面非常有经验的人能证实这一点。喜欢肯定的表演