How to create dynamic router for nested items in a sidebar with multilevel dropdown?

Viewed 233

This is my code currently but the path is not dynamic, everytime when there is a new section in the dropdown I have to hard code the path, is there anyway that I can write a function to auto generate those paths? (The first one is generating the multilevel sidebar, the second file is the router, and the third file is the content in the pages when you click on a section in the sidebar)

import React from "react";
import * as AiIcons from "react-icons/ai";
import * as IoIcons from "react-icons/io";

export const SidebarData = [
  {
    label: "Vertical App",
    path: "/verticalapp",
    icon: <AiIcons.AiFillHome />,
    id: 1,
    branches: [
      {
        label: "Weather App",
        path: "/verticalapp/weatherapp",
        icon: <IoIcons.IoIosPaper />,
        id: 2,
        branches: [],
      },
      {
        label: "Occupancy App",
        path: "/verticalapp/occupancyapp",
        icon: <IoIcons.IoIosPaper />,
        id: 3,
        branches: [],
      },
    ],
  },
  {
    label: "Company",
    path: "/company",
    icon: <IoIcons.IoIosPaper />,
    id: 4,
    branches: [
      {
        label: "Reseller",
        path: "/company/reseller",
        icon: <IoIcons.IoIosPaper />,
        id: 5,
        branches: [
          {
            label: "Client 1",
            path: "/company/reseller/client1",
            icon: <IoIcons.IoIosPaper />,
            id: 6,
            branches: [
              {
                label: "Client 11",
                path: "/company/reseller/client11",
                icon: <IoIcons.IoIosPaper />,
                id: 7,
                branches: [],
              },
            ],
          },
          {
            label: "Client 2",
            path: "/company/reseller/client2",
            icon: <IoIcons.IoIosPaper />,
            id: 8,
            branches: [
              {
                label: "Client 21",
                path: "/company/reseller/client21",
                icon: <IoIcons.IoIosPaper />,
                id: 9,
                branches: [],
              },
              {
                label: "Client 22",
                path: "/company/reseller/client22",
                icon: <IoIcons.IoIosPaper />,
                id: 10,
                branches: [],
              },
            ],
          },
        ],
      },
      {
        label: "Client",
        path: "/company/client",
        icon: <IoIcons.IoIosPaper />,
        id: 11,
        branches: [
          {
            label: "Client 3",
            path: "/company/client/client3",
            icon: <IoIcons.IoIosPaper />,
            id: 12,
            branches: [],
          },
          {
            label: "Client 4",
            path: "/company/client/client4",
            icon: <IoIcons.IoIosPaper />,
            id: 13,
            branches: [],
          },
        ],
      },
      {
        label: "Consumer",
        path: "/company/consumer",
        icon: <IoIcons.IoIosPaper />,
        id: 14,
        branches: [],
      },
    ],
  },
  
  {
    label: "Contact Us",
    path: "/contactus",
    icon: <IoIcons.IoMdHelpCircle />,
    id: 20,
    branches: [],
  },
];
import './App.css';
import Sidebar from './components/Sidebar';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import VerticalApp from './pages/VerticalApp';
//import { Company, Reseller, Client, Consumer, Client1, Client2 } from './pages/Company';
import {Company} from './pages/Company';

function App() {
  return (
    <Router>
      <Sidebar />
      <Switch>
        <Route path='/verticalapp' exact component={VerticalApp} />
        <Route path='/company' exact component={Company} />
        {/* <Route path='/company/:label' component={Company} /> */}
        {/* <Route path='/company/reseller' exact component={Reseller} />
        <Route path='/company/client' exact component={Client} />
        <Route path='/company/consumer' exact component={Consumer} />
        <Route path='/company/reseller/client1' exact component={Client1} />
        <Route path='/company/reseller/client2' exact component={Client2} /> */}
      </Switch>
    </Router>
  );
}

export default App;
import React from "react";

export const Company = () => {
  return (
    <div className="reports">
      <h1>Company</h1>
    </div>
  );
};

export const Reseller = () => {
  return (
    <div className="reports">
      <h1>Company/Reseller</h1>
    </div>
  );
};

export const Client = () => {
  return (
    <div className="reports">
      <h1>Company/Client</h1>
    </div>
  );
};

export const Consumer = () => {
  return (
    <div className="reports">
      <h1>Company/Consumer</h1>
    </div>
  );
};

export const Client1 = () => {
  return (
    <div className="reports">
      <h1>Company/Reseller/Client1</h1>
    </div>
  );
};

export const Client2 = () => {
  return (
    <div className="reports">
      <h1>Company/Reseller/Client2</h1>
    </div>
  );
};
1 Answers

You could add route props to the sidebarData and recursively build an array of routes.

Example:

const sidebarData = [
  {
    label: "Vertical App",
    path: "/verticalapp",
    icon: <AiIcons.AiFillHome />,
    id: 1,
    routeProps: {
      render: () => <h1>Vertical App</h1>
    },
    branches: [
      {
        label: "Weather App",
        path: "/verticalapp/weatherapp",
        icon: <IoIcons.IoIosPaper />,
        id: 2,
        branches: []
      },
      {
        label: "Occupancy App",
        path: "/verticalapp/occupancyapp",
        icon: <IoIcons.IoIosPaper />,
        id: 3,
        branches: []
      }
    ]
  },
  {
    label: "Company",
    path: "/company",
    icon: <IoIcons.IoIosPaper />,
    id: 4,
    routeProps: {
      component: Company
    },
    branches: [
      {
        label: "Reseller",
        path: "/company/reseller",
        icon: <IoIcons.IoIosPaper />,
        id: 5,
        routeProps: {
          component: Reseller
        },
        branches: [
          {
            label: "Client 1",
            path: "/company/reseller/client1",
            icon: <IoIcons.IoIosPaper />,
            id: 6,
            routeProps: {
              component: Client1
            },
            branches: [
              {
                label: "Client 11",
                path: "/company/reseller/client11",
                icon: <IoIcons.IoIosPaper />,
                id: 7,
                branches: []
              }
            ]
          },
          {
            label: "Client 2",
            path: "/company/reseller/client2",
            icon: <IoIcons.IoIosPaper />,
            id: 8,
            routeProps: {
              component: Client2
            },
            branches: [
              {
                label: "Client 21",
                path: "/company/reseller/client21",
                icon: <IoIcons.IoIosPaper />,
                id: 9,
                branches: []
              },
              {
                label: "Client 22",
                path: "/company/reseller/client22",
                icon: <IoIcons.IoIosPaper />,
                id: 10,
                branches: []
              }
            ]
          }
        ]
      },
      {
        label: "Client",
        path: "/company/client",
        icon: <IoIcons.IoIosPaper />,
        id: 11,
        routeProps: {
          component: Client
        },
        branches: [
          {
            label: "Client 3",
            path: "/company/client/client3",
            icon: <IoIcons.IoIosPaper />,
            id: 12,
            branches: []
          },
          {
            label: "Client 4",
            path: "/company/client/client4",
            icon: <IoIcons.IoIosPaper />,
            id: 13,
            branches: []
          }
        ]
      },
      {
        label: "Consumer",
        path: "/company/consumer",
        icon: <IoIcons.IoIosPaper />,
        id: 14,
        routeProps: {
          component: Consumer
        },
        branches: []
      }
    ]
  },

  {
    label: "Contact Us",
    path: "/contactus",
    icon: <IoIcons.IoMdHelpCircle />,
    id: 20,
    routeProps: {
      render: () => <h1>About Us</h1>
    },
    branches: []
  }
];

Compute the routes

const routes = (data) =>
  data
    // include only data items with route props
    .filter(({ routeProps }) => !!routeProps)
    // recursively get "nested" routes, flatten to single array
    .flatMap(({ branches, id, path, routeProps }) => [
      ...routes(branches),
      { id, path, ...routeProps }
    ]);

const getRoutes = (data) =>
  routes(data)
    // sort more specific routes before less specific routes
    .sort((a, b) => b.path.localeCompare(a.path))
    // map to Route component
    .map(({ id, path, ...routeProps }) => (
      <Route key={id} path={path} {...routeProps} />
    ));

...

<Switch>
  {getRoutes(sidebarData)}
</Switch>

Edit how-to-create-dynamic-router-for-nested-items-in-a-sidebar-with-multilevel-dropd

Related