React Router Dom doesn’t redirect to specified path on entering of wrong path after handling that. How do I fix it?

How do I handle wrong routes like localhost:4800/sajkfa to redirect to the not found component <Page404 />

As it stands, the dashboard layout renders when I enter a wrong path. The <DashboardLayout></DashboardLayout/> wrap the private routes of the App and contain the navigation for the protected routes.

Here is my Dashbaord Layout:

<div className="dashboard">
  <DashboardSidebar showSidebar={isVisible} closeSidebar={closeSidebar}/>
  <div className="dashboard__body">
    <DashboardHeader 
      title={title} 
      openSidebar={openSidebar}
    />
    <main className="dashboard__main">
      <div className="dashboard__container">
        {children}
      </div>
    </main>
  </div>
</div>

The {children} renders the current route component.

Here is my App Component that houses all the routes. The last code is meant to route to <Page404 /> if the path doesn’t match any component mapped to it.

<Switch>
    <Route exact path="/login" component={Login} />

    
     <DashboardLayout title={title}>

       <PrivateRoute exact path="/" component={Home}/>

       <PrivateRoute exact path="/a" component={A}/>

       <PrivateRoute exact path="/b" component={B}/>

     </DashboardLayout>

    <Route path="*" component={Page404} />
 </Switch>

Here is the code that handles the private routes:

const PrivateRoute = ({ component: Component, title, ...rest }) => {
  const { loading, data } = useSelector((state) => state.login)
  return <Route {...rest} render={(props) => (
    data?.data?.token && !loading
      ? <Component {...props} title={title}/>
      : <Redirect to='/login' />
    )} 
  />
}

The code above routes the user to the Login Component if the user doesn’t have an auth token on entering a valid path.

I expect the line of code below in my <App /> below to route to <Page404 /> by default if user enters wrong route but it stays on the wrong route and displays my empty <DashboardLayout /> with no content which is never supposed to be displayed to the user except when logged in. Here is the line:

<Route path="*" component={Page404} />

How do I get it to work? Thanks in advance.

Answer

The <Switch /> should have <Route /> as direct children and does not check if you pass other types of children.

If you pass <DashboardLayout> as a child, that route is always matched => <DashboardLayout /> is rendered => <Route path="*" component={Page404} /> is not rendered.

The quickest fix is to move the <DashboardLayout /> inside the <PrivateRoute />

const PrivateRoute = ({ component: Component, title, ...rest }) => {
    const { loading, data } = useSelector((state) => state.login);
    return (
        <Route
            {...rest}
            render={(props) =>
                data?.data?.token && !loading ? (
                    <DashboardLayout title={title}>
                        <Component {...props} title={title} />
                    </DashboardLayout>
                ) : (
                    <Redirect to="/login" />
                )
            }
        />;
    );
};