为什么我的 navbaropen 状态没有在窗口 addeventlistener (React js) 中更新?

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

条件有效,但由于某种原因 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;

我希望每当我单击屏幕上除屏幕之外的任何位置时都能够关闭导航栏。

javascript reactjs react-hooks frontend
1个回答
0
投票

您的点击事件监听器是一个无意的副作用。将其移动到

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;
  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" />

© www.soinside.com 2019 - 2024. All rights reserved.