React Routes: 404page is always shown at the bottom of all pages of the site, except for the main page

Viewed 108

I need to display a custom 404 page if there is no such page on the site. For this, the <Route path='*' element={<MissingPage />} /> route is introduced and it manages this matter. BUT apart from this, 404 page is displayed at the bottom on all pages on the site, except for the main one. I wish it didn't show up

"dependencies":
  "@craco/craco": "^6.4.3",
  "@emotion/react": "^11.9.0",
  "react": "^18.1.0",
  "react-dom": "^18.1.0",

"devDependencies":
  "react-router-dom": "^6.3.0"

Bottom is an example of one of the routes

Others are similar to this one, at the end the route to the main page is inserted along the path "/" and 404 along the path "*"

Already tried 'exact' property. Unfortunately, it remained in the old versions

return (
    <ThemeProvider theme={theme}>
        <SharedContextProvider>
            <div className='main'>
                <BrowserRouter>
                    <SharedDataManagement>
                        <Fragment>
                            <AuthRoutes />
                            <DashboardRoutes />
                            <SubscriptionsContextProvider>
                                <SubscriptionsRoutes />
                            </SubscriptionsContextProvider>
                            <PaymentRoutes />
                            <CommitmentRoutes />
                            <CoursesRoutes />
                            <ContactUsRoutes />
                            <ErrorsRoutes />
                            <Routes>
                                <Route path='/' element={<HomePageComponent />} />
                                <Route path='*' element={<MissingPage />} />
                            </Routes>
                        </Fragment>
                    </SharedDataManagement>
                </BrowserRouter>
            </div>
        </SharedContextProvider>
    </ThemeProvider>
  )
}

...

export function PaymentRoutes() {
    return (
        <PaymentContextProvider>
            <Routes>
                <Route path='/payment' element={<PaymentPage />} />
                <Route path='/payment/success' element={<SubscriptionPage />} />
            </Routes>
        </PaymentContextProvider>
    )
}

...

export function CommitmentRoutes() {
    return (
        <Routes>
            <Route path='/privacy-policy' element={<PrivacyPolicyPage />} />
            <Route path='/terms-and-conditions' element={<TermsAndConditionsPage />} />
            <Route path='/cookie' element={<CookiePage />} />
        </Routes>
    )
}
3 Answers

Issue

The issue is that the code is rendering several sets of Routes components via the custom routes components as well as the final Routes that is rendering a "404" route. The last Routes is always rendered and when it doesn't render a route that matches the current URL it renders its "404" route.

Solution

I suggest converting all the custom routes components into layout route components and render all the routes into a single Routes component with the single "404" route.

Example:

import { Outlet } from 'react-router-dom';

export function PaymentLayout() {
  return (
    <PaymentContextProvider>
      <Outlet />
    </PaymentContextProvider>
  )
}

...

<BrowserRouter>
  <SharedDataManagement>
    <Routes>
      <Route element={<AuthLayout />}>
        ....
      </Route>
      <Route element={<DashboardLayout />}>
        ....
      </Route>
      <Route element={<SubscriptionsLayout />}>
        ....
      </Route>
      <Route element={<PaymentLayout />}>
        <Route path='/payment' element={<PaymentPage />} />
        <Route path='/payment/success' element={<SubscriptionPage />} />
      </Route>
      <Route element={<CommitmentLayout />}>
        <Route path='/privacy-policy' element={<PrivacyPolicyPage />} />
        <Route path='/terms-and-conditions' element={<TermsAndConditionsPage />} />
        <Route path='/cookie' element={<CookiePage />} />
      </Route>
      <Route element={<CoursesLayout />}>
        ....
      </Route>
      <Route element={<ContactUsLayout />}>
        ....
      </Route>
      <Route element={<ErrorsLayout />}>
        ....
      </Route> 
      <Route path='/' element={<HomePageComponent />} />
      <Route path='*' element={<MissingPage />} />
    </Routes>
  </SharedDataManagement>
</BrowserRouter>

You could use react-router Switch component to render only one route per url :

return (
  <Switch>
    <Route exact path="/">
      <HomePageComponent />
    </Route>
    <Route path="/my-first-path">
      <MyFirstComponent />
    </Route>
    <Route path="/my-second-path">
      <MySecondComponent />
    </Route>
    <Route>
      <MissingPage />
    </Route>
  </Switch>
);

Issue

The issue is that the code is rendering several sets of Routes components via the custom routes components as well as the final Routes that is rendering a "404" route. The last Routes is always rendered and when it doesn't render a route that matches the current URL it renders its "404" route.

Solution

I was already given a solution, but it was important for me to set the project structure in its current form.

Therefore, for starters, I found the config.ts file here I entered all my routes as an array of strings

export const knownRoutes: string[] = [
    ...
    'payment', 
    'success', 
    'login' , 
    'register', 
    ...
]

Then I introduced the unknown route logic

export function App() {
    const isUnknownRoutes = knownRoutes.find((route) => (window.location.href).includes(route))
    
    return (
        <ThemeProvider theme={theme}>
            <SharedContextProvider>
                <div className='main'>
                    <BrowserRouter>
                        <SharedDataManagement>
                            <Fragment>
                                <AuthRoutes />
                                <DashboardRoutes />
                                <SubscriptionsContextProvider>
                                    <SubscriptionsRoutes />
                                </SubscriptionsContextProvider>
                                <PaymentRoutes />
                                ...
                                <Routes>
                                    <Route path='/' element={<HomePageComponent />} />
                                    {!isUnknownRoutes && (<Route path='*' element={<MissingPage />} />)}
                                </Routes>
                            </Fragment>
                        </SharedDataManagement>
                    </BrowserRouter>
                </div>
            </SharedContextProvider>
        </ThemeProvider>
    )
}
Related