Javascript 导航到下一页时如何正确清理“打开”菜单

Javascript 导航到下一页时如何正确清理“打开”菜单,javascript,reactjs,typescript,use-effect,Javascript,Reactjs,Typescript,Use Effect,我创建了简单但有效的下拉菜单。在此示例中,菜单只包含文本“菜单”,没有样式 单击“打开菜单”按钮时,应用程序将显示包含菜单的div,并将eventListener添加到文档单击事件中。当添加eventListener并且用户单击文档中的任意位置时,函数检查单击是否发生在菜单中,如果发生,则不执行任何操作。如果单击位于菜单之外,它将删除eventHandler并关闭菜单 这条裙子有毛病吗?这方面的主要问题是,当我单击页面上的任何链接时,如果菜单处于打开状态,我会收到以下警告: js:1警告:无法对

我创建了简单但有效的下拉菜单。在此示例中,菜单只包含文本“菜单”,没有样式

单击“打开菜单”按钮时,应用程序将显示包含菜单的
div
,并将eventListener添加到文档单击事件中。当添加eventListener并且用户单击文档中的任意位置时,函数检查单击是否发生在菜单中,如果发生,则不执行任何操作。如果单击位于菜单之外,它将删除eventHandler并关闭菜单

这条裙子有毛病吗?这方面的主要问题是,当我单击页面上的任何链接时,如果菜单处于打开状态,我会收到以下警告:

js:1警告:无法对未安装的组件执行React状态更新。这是一个no-op,但它表示应用程序中存在内存泄漏。要修复此问题,请取消useEffect清理函数中的所有订阅和异步任务

我添加了
useffect
cleanup函数来删除菜单打开时的eventHandler,但这并没有帮助,我仍然收到相同的错误消息

你能指出我做错了什么吗

const DropDown = () => {
  const [open, setOpen] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  const closeMenu = (event: MouseEvent) => {
    if (event.target && event.target instanceof HTMLElement && ref.current) {
      if (ref.current.contains(event.target)) return;
    }

    document.removeEventListener('click', closeMenu);
    setOpen(false);
  };

  const toggleMenu = () => {
    if (!open) {
      document.addEventListener('click', closeMenu);
      setOpen(true);
    } else {
      document.removeEventListener('click', closeMenu);
      setOpen(false);
    }
  };

  useEffect(() => {
    return () => {
      if (open) {
        document.removeEventListener('click', closeMenu);
        setOpen(false);
      }
    };
  }, [closeMenu]);

  return (
    <>
      <button onClick={toggleMenu}>open menu</button>
      {open && <div ref={ref}>menu</div>}
    </>
  );
};

export default DropDown;
const下拉列表=()=>{
const[open,setOpen]=useState(false);
const ref=useRef(null);
const closeMenu=(事件:MouseEvent)=>{
if(HTMLElement和ref.current的event.target和event.target实例){
if(ref.current.contains(event.target))返回;
}
document.removeEventListener(“单击”,关闭菜单);
setOpen(假);
};
常量切换菜单=()=>{
如果(!打开){
document.addEventListener(“单击”,关闭菜单);
setOpen(真);
}否则{
document.removeEventListener(“单击”,关闭菜单);
setOpen(假);
}
};
useffect(()=>{
return()=>{
如果(打开){
document.removeEventListener(“单击”,关闭菜单);
setOpen(假);
}
};
},[closeMenu]);
返回(
打开菜单
{打开&菜单}
);
};
导出默认下拉列表;

我认为问题是由
setOpen(false)引起的useffect
hook中的code>:当组件卸载时调用clean-up函数,因此设置其状态没有意义。出于同样的原因,检查菜单是否打开是多余的;如果菜单已卸载,则可以删除事件处理程序

尝试:

const下拉列表=()=>{
const[open,setOpen]=useState(false);
const ref=useRef(空);
/*
*“useCallback()”钩子将避免不必要的重新创建
*每次重新渲染时的函数
*/
const closeMenu=useCallback((事件:MouseEvent)=>{
if(HTMLElement和ref.current的event.target和event.target实例){
if(ref.current.contains(event.target))返回;
}
/* 
*您不需要在此处删除事件处理程序
*您可以在安装和安装组件时创建它
*通过“useEffect()”挂钩卸载时将其卸下
*/
//document.removeEventListener(“单击”,关闭菜单);
setOpen(假);
}, []);
常量切换菜单=()=>{
/*
*这不是必需的,您可以在一行中完成。
*实际上,您可以完全删除该函数并
*直接从按钮调用“setOpen(!open)”:
*{setOpen(!open)}}>
*/
//如果(!打开){
//document.addEventListener(“单击”,关闭菜单);
//setOpen(真);
//}否则{
//document.removeEventListener(“单击”,关闭菜单);
//setOpen(假);
//}
setOpen(!open);
};
useffect(()=>{
document.addEventListener(“单击”,关闭菜单);
return()=>{
document.removeEventListener(“单击”,关闭菜单);
};
},[closeMenu]);
报税表(<
>
<
按钮onClick={
切换菜单
}>打开菜单{
打开&
菜单
}< /> ); };
导出默认下拉列表