React Bootstrap - Close NavDropdown on route change

Viewed 546

I'm using <NavDropdown> (link to docs) in a <Nav> component and it works great. The problem I have is that I can't close an open dropdown on route change. Here's an example of the code:

const menuItems = {
  "menu item": {
    title: "Menu Title",
    links: [
      {
        text: "Link Text",
        route: "/route-to-page"
      },
      {
        text: "Link Text 2",
        route: "/route-to-page-2"
      }
    ]
  }
};

<Nav>
  {menuItems.map((item) => (
    <NavDropdown title={Menu[item].title}>
      .. Some menu items...
    </NavDropdown>
  )}
</Nav>

I would like to be able to add an onClick handler to links that closes any open dropdowns, but I can't see an effective way to do this.

I'd appreciate any help.

3 Answers

what do you mean you cant ? of-curse you can

import {Link} from 'react-router-dom'

<Nav.Link as="a" to="/" onClick={e=> {
 // close modal
}}>
Link
</Nav.Link>

I have come up with a solution for this, but it is a bit clunky. Here goes.

First of all, we create an object in state.

    const resetMenu = {
        dropdown1: false,
        dropdwon2: false,
        // etc.
    };
    const [menu, setMenu] = useState({ ...resetMenu });

resetMenu could be generated dynamically.

We can then use react-router-dom's useLocation to watch for route changes.

import { useLocation } from 'react-router-dom';
const location = useLocation();

Then we can use React useEffect hook to listen out for changes to that location and set values in our menu state to false.

useEffect(() => {
    setMenu({...resetMenu});
  }
}, [location]);

Finally, we can use the show prop to control whether the dropdown is visible, and an onClick on the toggle to change the value in menu state.

<Nav>
  {menuItems.map((item) => (
    <NavDropdown 
      title={menu[item].title}
      show={menu[item]}
      onClick={() =>
        setMenu((prevState) => ({
            ...resetMenu,
            [item]: !prevState[item],
        }))
    >
      .. Some menu items...
    </NavDropdown>
  )}
</Nav>

I hope that helps someone else with this same problem.

I have got this to work as follows:

import NavDropdown from 'react-bootstrap/NavDropdown';
import {Link} from 'react-router-dom';

<NavDropdown title="Maintenance" id="navigation-dropdown">
  <NavDropdown.Item to="/categories" as={Link}>Categories</NavDropdown.Item>
  <NavDropdown.Item to="/account-types" as={Link}>Account Types</NavDropdown.Item>
</NavDropdown>

It doesn't restart the app when an item is selected and the menu closes. You could populate the items programmatically.

Related