How to add react routing to AntD horizontal Menu?
Asked Answered
M

3

5

I have the below component as the main layout. When I click on the menu item, I want them to navigate to the home, holiday calendar, and event pages. What can I do with this horizontal menu? The below code shows the main layout wrapped around the above pages. I am using AntD and react-router. this main layout is wrapped around all other routers.

import { Layout, Menu, Button, Avatar, Row, Col, Space, Dropdown } from "antd";
import React, { useState } from "react";
import { Outlet } from "react-router-dom";

const navigation = [
  { label: "Home", key: 1 },
  { label: "Holiday Calendar", key: 2 },
  { label: "Event", key: 3 },
];

const MainLayout = () => {

  const [open, setOpen] = useState(false);

  const showDrawer = () => {
    setOpen(true);
  };

  const onClose = () => {
    setOpen(false);
    window.dispatchEvent(new Event("loadHolidayCalander"));
  };

  const handleLogOut = () => {
    localStorage.removeItem("access-token");

  };
  const menu = (
    <Menu
      items={[
        {
          key: "1",
          label: <Button onClick={handleLogOut}>Log out</Button>,
        },
      ]}
    ></Menu>
  );

  return (
    <Layout style={{backgroundColor:"white"}}>      
        <Row style={{ backgroundColor:"#404140"}}>
          <Col
          style={{padding:5, margin:0, height:48}}
            flex="300px"
           >
            <a href="/holiday-calander">
              <img src="/logo.png" alt="logo" style={{ height: 38 }} />
            </a>
          </Col>
          <Col>
            <Menu              
              theme="dark"
              mode="horizontal"
              defaultSelectedKeys={["2"]}
              items={navigation}
            />
          </Col>
          <Col
            flex="auto"
            style={{

              padding:5

            }}
          >
            <div style={{ position: "absolute", right: "5px" }}>
              <Space size={20}>
                <Dropdown overlay={menu} placement="topRight" arrow>
                  <Avatar  style={{ width: 38, height:38 }} />
                </Dropdown>
              </Space>
            </div>
          </Col>

        </Row>
        
    
      <Layout
        style={{
          padding: 0,
          backgroundColor: "white",
          marginLeft:28,
          marginRight:28,
        }}
      >

        <Outlet />

      </Layout>
    </Layout>
  );
};

export default MainLayout;


Munoz answered 6/11, 2022 at 18:34 Comment(0)
Z
7

You can add an onClick handler to the Menu component, which will be passed an object with the key property you can search the navigation array for the matching element.

Add a link target to the navigation array elements.

import { ..., useNavigate, ... } from 'react-router-dom';

...

const navigation = [
  { label: "Home", key: 1, target: "/" },
  { label: "Holiday Calendar", key: 2, "/holidaycalendar" },
  { label: "Event", key: 3, "/event" },
];

...

const navigate = useNavigate();

const handleMenuClick = ({ key }) => {
  const { target } = navigation.find(item => item.key === key) || {};
  if (target) {
    navigate(target);
  }
};

...

<Menu              
  theme="dark"
  mode="horizontal"
  defaultSelectedKeys={["2"]}
  items={navigation}
  onClick={handleMenuClick}
/>

An improvement could be to make the key property the link target.

import { ..., useNavigate, ... } from 'react-router-dom';

...

const navigation = [
  { label: "Home", key: "/" },
  { label: "Holiday Calendar", key: "/holidaycalendar" },
  { label: "Event", key: "/event" },
];

...

const navigate = useNavigate();

const handleMenuClick = ({ key }) => {
  if (key) {
    navigate(key);
  }
};

...

<Menu              
  theme="dark"
  mode="horizontal"
  defaultSelectedKeys={["/holidaycalendar"]}
  items={navigation}
  onClick={handleMenuClick}
/>
Zeller answered 6/11, 2022 at 18:59 Comment(0)
T
6

Actually you can pass Link component from rrd to label property in Menu.item as state in this link.

Example :

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

items = [
    {
        key: '/home',
        label: <Link to='/home'>Home</Link>,
        icon: <SomeIcon />,
    },
    {
        key: '/menu',
        label: 'This is parent menu',
        icon: <SomeIcon />,
        children: [
            {
                key: '/menu-1',
                label: '<Link to='/menu-1'>Sub Menu 1</Link>,
                icon: <MenuIcon1 />,
            },
            {
                key: '/menu-2',
                label: '<Link to='/menu-2'>Sub Menu 2</Link>,
                icon: <MenuIcon2 />,
            },
    },
]

Thrawn answered 9/4, 2023 at 20:31 Comment(2)
This should be the correct solution, as this is also working with browser native features like middle mouse or control + clickHabiliment
But this does not make the Menu buttons active in any way.Pahari
P
0

If you're using React Router 6, you can set id for each of your routes and use it to match it to the correct Menu item.

import { useLocation, matchRoutes, createBrowserRouter } from 'react-router-dom';

...

const routes = [
  { id: 'layout', path: '/', element, children: [
    { id: 'home', index: true, element },
    ...
  ] },
  ...
];

const router = createBrowserRouter(routes);

...

const currentRoutes = matchRoutes(routes, location);
const currentRoutesIds = currentRoutes?.map((r) => r.route.id);

...

const items = [
  {
    key: 'home',
    label: <NavLink to="/">Home</NavLink>,
  },
  {
    key: 'other',
    label: <NavLink to="/other">Some other route</NavLink>,
  },
  ...
];

...

<Menu              
  selectedKeys={currentRoutesIds}
  items={items}
/>
Psychogenic answered 22/10 at 8:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.