导航到另一条路线时,React 移动导航不会自动关闭

React mobile nav won't close automatically when navigating to another route

我按照 this 教程构建了一个移动导航,这是一个很棒的教程,但是我卡住了。

点击导航图标时,移动导航下拉菜单打开和关闭没有问题。但是,当我单击下拉菜单 link 并导航到另一个页面时,移动导航将保持打开状态,除非我自己手动将其关闭。

如何在路线改变时关闭移动导航?

我感觉它的 Navbar 文件不太对劲!但我似乎无法理解它。任何建议都会很棒。

谢谢。

/// Navbar.jsx

import { Alert, Stack } from '@mui/material'
import React, { useContext, useState } from 'react'
import '../../styles/nav.css'
import { UserContext } from '../Contexts/User-Context'

const Navbar = (props) => {
  const { loggedInUser } = useContext(UserContext)
    const [open, setOpen] = useState(false)

    const showSidebar = () => {
              setOpen(!open)
          }

    const DropdownItem = (props) => {
        return (
            <div>
                { props.children }
            </div>
        )
    }

  return (
      <div className='navbar'>
        <h2 className='logo'>NC Games</h2>
        <ul className='navbar-list'>
            { props.children }
        </ul>
        </div>
  ) 
}

export default Navbar
/// DropdownMenu.jsx

import React, { useContext, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { UserContext } from '../Contexts/User-Context'

const DropdownMenu = () => {
    const { loggedInUser, setLoggedInUser } = useContext(UserContext)
    const [open, setOpen] = useState(false)

    const logOut = () => {
      setLoggedInUser({ user: undefined })
      
    }
    
    const DropdownItem = (props) => {
          return (
              <div className='menu-item'>
                  { props.children }
               </div>
          )
      }

  

  return loggedInUser ? (
    <><div className='dropdown'>
          <Link to={`/users/${loggedInUser.username}`}>
          <DropdownItem className='nav-profile'>
              <img className='nav-profile-pic' alt={loggedInUser.username} src={loggedInUser.avatar_url} />
          </DropdownItem>
       </Link>
      <Link to={`/categories`}>
      
      <DropdownItem>Categories</DropdownItem>
      </Link>
      <Link to={`/reviews`}>
      <DropdownItem>Reviews</DropdownItem>
      </Link>
      <Link to={`/users`}>
      <DropdownItem>Users</DropdownItem>
      </Link>
      <Link onClick={() => logOut()} to={`/`}>
      <DropdownItem>Log out</DropdownItem>
      </Link>
    </div>
    </>  
  ) : (
    null
  )
}

export default DropdownMenu
/// NavItem.jsx

import React, { useState } from 'react'
import '../../styles/nav.css'

const NavItem = (props) => {
    const [open, setOpen] = useState(false)
    console.log(open, "<< open");

    return (
        <li className='nav-item'>
            <div onClick={() => setOpen(!open)}>
                { props.icon }
            </div>
            { open && props.children }
        </li>

    )
}

export default NavItem
// App.jsx

function App() {
  // const [user, setUser] = useState(null);
  const [loggedInUser, setLoggedInUser] = useState(null);
  const [loggedIn, setLoggedIn] = useState(false);
  // const response = await axios.post()

  const saveLoggedInUser = () => {
    localStorage.setItem("user", JSON.stringify(loggedInUser));
  };

  const getLoggedInUser = () => {
    if (localStorage.getItem("user") === null) {
      localStorage.setItem("user", JSON.stringify(null));
    } else {
      let userLocal = JSON.parse(localStorage.getItem("user"));
      setLoggedInUser(userLocal);
      setLoggedIn(true);
    }
  };

  useEffect(() => {
    getLoggedInUser();
  }, []);

  useEffect(() => {
    saveLoggedInUser();
  }, [loggedInUser, loggedIn]);

  useEffect(() => {
    window.scrollTo(50, 50)
  }, [])

  const isLoggedIn = loggedInUser !== null;

  return (
    <BrowserRouter>
      <UserContext.Provider
        value={{ loggedInUser, setLoggedInUser, isLoggedIn }}
      >
        <div className="App">
          <Navbar>
            <NavItem icon={<MenuRoundedIcon />}>
              <DropdownMenu />
            </NavItem>
          </Navbar>
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/categories" element={<Categories />} />
            <Route path="/reviews/:category" element={<ReviewList />} />
            <Route path="/reviews" element={<ReviewList />} />
            <Route path="/review/:review_id" element={<ReviewPage />} />
            <Route path="/users" element={<Users />} />
            <Route path="/users/:username" element={<User />} />
          </Routes>
        </div>
      </UserContext.Provider>
    </BrowserRouter>
  );
}
/// Nav.css

* {
  margin: 0px;
}

:root {
  --bg: #242526;
  --bg-accent: #484a4d;
  --nav-size: 60px;
  --border: 1px solid #474a4d;
  --border-radius: 8px;
  --speed: 500ms;
  /* margin-top: 75px; */
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
} 


a {
  /* color: #dadce1; */
  text-decoration: none;
}

.logo {
  color: #dadce1;
  margin: 0px;
  display: flex;
  align-items: center;
}

.navbar {
  height: var(--nav-size);
  background-color: var(--bg);
  padding: 0 1rem;
  border-bottom: var(--border);
  display: flex;
  justify-content: space-between;
  position: fixed;
  z-index: 1000;
  top: 0;
  width: 100%;
}

.navbar-list {
  max-width: 100%;
  height: 100%;
  display: flex;
  justify-content: flex-end;
}

.nav-item {
  width: calc(var(--nav-size) * 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 25px;
  color: #dadce1;
}

.icon-button {
  --button-size: calc(var(--nav-size) * 0.5);
  width: var(--button-size);
  height: var(--button-size);
  /* background-color: #484a4d;  */
  border-radius: 50%;
  padding: 5px;
  margin: 2px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.dropdown {
  position: absolute;
  z-index: 1;
  top: 56px;
  width: 300px;
  transform: translateX(-35%);
  background-color: var(--bg);
  border: var(--border);
  border-radius: var(--border-radius);
  padding: 1rem;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  opacity: 1;
}

.menu-item {
  height: 50px;
  display: flex;
  flex-direction: column;
  text-align: center;
  align-items: center;
  justify-content: center;
  border-radius: var(--border-radius);
  /* transition: background var(--speed);  */
  padding: 0.5rem;
}

 .menu-item:hover {
  background-color: #525357;
} 

.nav-profile-pic {
  max-width: 75px;
  padding-bottom: 40px 0px 40px 0px;
  object-fit: contain;
  overflow: hidden;
  border-radius: 50%;
}

您是否在每条路线中定义了 NavBar 组件?

我认为如果您将 NavBar 移动到每个页面,那么默认情况下 header / navbar 应该在每次路线更改时重新初始化。

您还可以使用 useLocation() 并从中解构路径名。然后使用 useEffect 监视更改并关闭更改下拉列表:

 const { path } = useLocation();
  useEffect(() =>{
    setDropDownOpen(false);
  }, [path])