'react-router v5 with router-config: Redirect to subroute

I have an app which has all main pages on a SideBar (Dashboard, Reporting, etc..). The main page could contain itself a TopBar with navlink to sub-routes. For what I did until know, if a user click on a route with sub-routes, it only renders the topbar : he has to click a second time on a subroute. I would like to automatically render the first subroute. How can I do that?

const routes = [
    {
        label: "Dashboard",
        path: "/dashboard",
        component: DashboardComponent,
      },
      { 
        label: "Reporting",
        path: "/reporting",
        component: ReportSelection,
    },
    {
        label: "Sales Data",
        subLabel: "All tracked sales, leads and booked calls",
        path: "/sales-data",
        routes: [
            {
                label: "Sales",
                path: "/sales-data/sales",
                component: () => <SalesComponent calls={false}/>,
            },
            {
                label: "Leads",
                path: "/sales-data/leads",
                component: LeadsComponent,
            },
            {
                label: "Calls",
                path: "/sales-data/calls",
                component: () => <SalesComponent calls={true}/>,
            },
            {
                label: "Phone closing",
                path: "/sales-data/phone-closing",
                component: PhoneClosingComponent,
            }
        ]
    },
]


function RouteWithSubRoutes(route) {
    return (
      <Route
        path={route.path}
        render={props => {
            return (
          // pass the sub-routes down to keep nesting
          route.routes?.length > 0 ? 
            <SubPage {...props} route={route} /> :
            <route.component {...props} routes={route.routes} />
        )}}
      />
    );
}

/**
 * You may have some routes with child routes, such as "sales-data" route which has four subroutes. In that case, use SubPage component to render a Navbar to the top with links to subroutes.
 * @param route The route with subroutes. 
 * @returns 
 */
function SubPage({ route }) {
    console.log(route);
    return (
        <div>
            <HPageHeader title={route.label} subtitle={route.subLabel}>
                {route.routes.map((route, _idx) => (
                        <NavLink to={route.path}>{route.label}</NavLink>
                ))}
            </HPageHeader>
    
            <Switch>
            {route.routes.map((route, i) => (
                <RouteWithSubRoutes key={i} {...route} />
            ))}
            </Switch>
        </div>
    );
}

/**
 * This component is the root of the application. It contains :
 * - The router
 * - The topbar 
 * - The Sidebar, which contain Links to the first nodes of the app.
 * - The switch, who manage the component to render according to the route.
 */
export const App: React.FC = () => {

    const [collapsed, setCollapsed] = React.useState<boolean>(false);

    return (
        <HashRouter basename="/mh">

            <TopbarComponent
                onToggleCollapse={() => setCollapsed(collapsed => !collapsed)}
            ></TopbarComponent>

            <SidebarComponent routes={routes} collapsed={collapsed}/>

            <Switch>
                <div style={{marginLeft: collapsed ? "64px" : "220px"}}>
                    {routes.map((route, idx) => (
                        <RouteWithSubRoutes key={idx} {...route}/>
                    ))}
                </div>
            </Switch>
        </HashRouter>
    )
}


Solution 1:[1]

From what you describe it sounds like you are wanting a quasi-equivalent to a an index route, that is to say, to render a component when the URL path matches the parent path instead of one of the nested children paths. react-router-dom v5 Route components can take an array of paths. Specify the parent path along with the path of the first sub-route.

Example:

const routes = [
  {
    label: "Dashboard",
    path: "/dashboard",
    component: DashboardComponent,
  },
  { 
    label: "Reporting",
    path: "/reporting",
    component: ReportSelection,
  },
  {
    label: "Sales Data",
    subLabel: "All tracked sales, leads and booked calls",
    path: "/sales-data",
    routes: [
      {
        label: "Sales",
        path: ["/sales-data/sales", "/sales-data"],
        component: () => <SalesComponent calls={false} />,
      },
      {
        label: "Leads",
        path: "/sales-data/leads",
        component: LeadsComponent,
      },
      {
        label: "Calls",
        path: "/sales-data/calls",
        component: () => <SalesComponent calls={true} />,
      },
      {
        label: "Phone closing",
        path: "/sales-data/phone-closing",
        component: PhoneClosingComponent,
      }
    ]
  },
]

In case there's any conflict with route paths and the Switch component you may want to use the exact prop on the Route components.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Reese