条件有效,但由于某种原因,setNavbarOpen(False)不起作用

以下是代码:

import { useState } from 'react';

const Navbar = () => {
  const [navbarOpen, setNavbarOpen] = useState(false);

  window.addEventListener('click', (e)=> {
    e.stopImmediatePropagation()
    const navbar = document.querySelector('.navbar')
    if (!navbar.contains(e.target)) {
      setNavbarOpen(false)
      console.log('done')
    }
  })
  return (
    <nav className="navbar">
      <button
        className="toggle"
        onClick={() => setNavbarOpen((prev) => !prev)}
      >
        {navbarOpen ? 'close' : 'open'}
      </button>
      <ul className={`menu-nav${navbarOpen ? ' show-menu' : ''}`}>
        <li>change background</li>
      </ul>
    </nav>
  );
};
export default Navbar;

我希望只要我点击屏幕上的任何地方,就可以关闭导航栏.

推荐答案

您的单击事件侦听器是一个无意的副作用.它不是作为Reaction组件生命周期的一部分创建的.

将其移动到useEffect钩子中以实例化侦听器.不要忘记返回一个清除函数来删除侦听器.

const Navbar = () => {
  const [navbarOpen, setNavbarOpen] = React.useState(false);

  React.useEffect(() => {
    const handler = (e) => {
      e.stopImmediatePropagation();
      const navbar = document.querySelector(".navbar");
      if (!navbar.contains(e.target)) {
        setNavbarOpen(false);
        console.log("done");
      }
    };

    window.addEventListener("click", handler);
    () => {
      window.removeEventListener("click", handler);
    };
  }, []);

  return (
    <nav className="navbar">
      <p>Click outside me to toggle closed</p>
      <button className="toggle" onClick={() => setNavbarOpen((prev) => !prev)}>
        {navbarOpen ? "close" : "open"}
      </button>
      <ul className={`menu-nav ${navbarOpen ? "show-menu" : ""}`}>
        <li>change background</li>
      </ul>
    </nav>
  );
};

const rootElement = document.getElementById("root");
const root = ReactDOM.createRoot(rootElement);

root.render(
  <React.StrictMode>
    <Navbar />
  </React.StrictMode>
);
.navbar {
  border: 1px solid green;
}

.menu-nav {
  overflow: hidden;
  height: 0;
  margin: 0;
  transition: all;
}

.show-menu {
  height: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root" />

Javascript相关问答推荐

如何使用JavaScript用等效的功能性HTML替换标记URL格式?

是什么原因导致此Angular 16应用程序中类型错误时属性结果不存在?

materialized - activeIndex返回-1

react/redux中的formData在expressjs中返回未定义的req.params.id

我不知道为什么setwritten包装promise 不能像我预期的那样工作

如何在angular中从JSON值添加动态路由保护?

如何在mongoose中链接两个模型?

如何粗体匹配的字母时输入搜索框使用javascript?

将现场录音发送到后端

将旋转的矩形zoom 到覆盖它所需的最小尺寸&S容器

当Redux提供程序访问Reduxstore 时,可以安全地从Redux提供程序外部调用钩子?

保持物品顺序的可变大小物品分配到平衡组的算法

Chart.js-显示值应该在其中的引用区域

在SHINY R中的嵌套模块中,不能使用Java代码

JavaScript&;Reaction-如何避免在不使用字典/对象的情况下出现地狱?

MUI迷你图:如何将$符号添加到MUI迷你图中的工具提示数据

在单击按钮时生成多个表单时的处理状态

在Puppeteer中使用promise进行日志(log)记录时出现TargetCloseError

如果我将高度设置为其内容的100%,则在Java脚本中拖动以调整面板大小时会冻结

JavaScript -如何跳过某个字符(S)来打乱字符串中的字符