React-Router: No Not Found Route

React-Router: No Not Found Route?

DefaultRoute and NotFoundRoute were removed in react-router 1.0.0.

I'd like to emphasize that the default route with the asterisk has to be last in the current hierarchy level to work. Otherwise it will override all other routes that appear after it in the tree because it's first and matches every path.

For react-router 1, 2 and 3

If you want to display a 404 and keep the path (Same functionality as NotFoundRoute)

<Route path='*' exact={true} component={My404Component} />

If you want to display a 404 page but change the url (Same functionality as DefaultRoute)

<Route path='/404' component={My404Component} />
<Redirect from='*' to='/404' />

Example with multiple levels:

<Route path='/' component={Layout} />
<IndexRoute component={MyComponent} />
<Route path='/users' component={MyComponent}>
<Route path='user/:id' component={MyComponent} />
<Route path='*' component={UsersNotFound} />
</Route>
<Route path='/settings' component={MyComponent} />
<Route path='*' exact={true} component={GenericNotFound} />
</Route>

For react-router 4 and 5

Keep the path

<Switch>
<Route exact path="/users" component={MyComponent} />
<Route component={GenericNotFound} />
</Switch>

Redirect to another route (change url)

<Switch>
<Route path="/users" component={MyComponent} />
<Route path="/404" component={GenericNotFound} />
<Redirect to="/404" />
</Switch>

The order matters!

404 page not found not working react-router v6 (using more than one param)

What makes you think that "/asoejdnxx/acnoiw" wouldn't be matched by path="/:category/:id" and render the "404" route and NotFound component instead?

For URL path "/asoejdnxx/acnoiw" the path="/:category/:id" will match it and render the Article component. It's at this point that Article needs to validate the route params it's consuming and if they are invalid, redirect to the 404 route.

I suggest actually creating a 404 route that you can redirect to.

Example:

<Routes>
<Route path="/" element={<Home />} />
<Route path="/:category/:id" element={<Article />} />
<Route path="notfound" element={<NotFound />} />
<Route path="*" element={<Navigate to="/notfound" replace />} />
</Routes>

In the Article component use a useEffect hook to redirect to "/notfound" under the correct circumstances.

Example:

const { category, id } = useParams();
const navigate = useNavigate();

...

useEffect(() => {
if (/* invalid route params */) {
navigate("/notfound", { replace: true });
}
}, [category, id, navigate]);

react router dom v6 doesnt redirect to not found

You still need a path for your not found Route and just have it as a wildcard.

<Route path="*" element={<NotFound />} />

But if you are actually wanting the url to redirect to not-found then just have the Navigate component in there

import { Navigate } from 'react-router-dom'

<Route path="*" element={<Navigate to="not-found"/>} />

react router v4 default page(not found page)

React Router's No Match documentation covers this. You need to import the <Switch> component, then you can remove the path attribute altogether.

A <Switch> renders the first child <Route> that matches. A <Route> with no path always matches

This is the example that uses:

<Router>
<div>
<Switch>
<Route path="/" exact component={Home}/>
<Redirect from="/old-match" to="/will-match"/>
<Route path="/will-match" component={WillMatch}/>
<Route component={NoMatch}/>
</Switch>
</div>
</Router>

So in your case, you'd simply drop the path="*" and introduce the <Switch>:

<Switch>
<Route exact path="/" component={Home}/>
<Route path="/user" component={User}/>
<Route component={Notfound} />
</Switch>

Remember to include Switch to your import statement at the top.

React Router Not Showing 'Not Found' Page

This will not work as you are mentioning in the second route as any value can hold as /:topic, this route will get displayed when you add like this. Because, any segment that starts with a colon will be treated as a parameter. So the * route will not get displayed at any case!

How to show the Not Found route in react while using a route container?

I ended up having all my routes in 1 switch, and then having different layouts for authorised routes.

export default function App() {
return (
<BrowserRouter>
<Switch>
{pages.map(
(
{
exact,
path,
component: Component,
layout: Layout,
requiredPermissions
},
index
) => (
<Route
key={index}
exact={exact}
path={path}
render={props => (
<Layout requiredPermissions={requiredPermissions}>
<Component {...props} />
</Layout>
)}
/>
)
)}
<Route component={NotFound} />
</Switch>
</BrowserRouter>
);
}

Each page can be defined like so:

export const pages = [
// Public pages
{
exact: true,
path: routes.login,
component: LoginPage,
layout: PublicLayout,
requiredPermissions: []
},
// Authenticated pages
{
exact: true,
path: routes.dashboard,
component: Dashboard,
layout: AuthedLayout,
requiredPermissions: []
},
...

The token handling would be handled in "AuthedLayout":

export default function AuthedLayout(props) {
const { loading, token, name, refreshError } = useCheckAccessToken();
const userPermissions = GetUserPermissions(token);

return !refreshError ? (
<Fragment>
<LoadingOverlay loadingStatus={loading} />
<NavBar name={name} />
<props.children.type token={token} userPermissions={userPermissions} />
</Fragment>
) : !(!loading && token && name && !refreshError) ? (
<Redirect to="/login" />
) : (
"Unhandled Exception."
);
}

Hope these helped someone.

React router v6 not rendering anything on / route. Rest all route is working fine

It seems you are over-complicating the routes a bit, specifically what you are wanting to be a layout route.

Using a layout route and Outlet components

The layout routes should omit the path prop. This allows the nested Route components to render their element prop into the layout route component's Outlet (i.e. both Layout and ProtectedRoute component's Outlet).

Example:

const NavigationRoutes = () => (
<Routes>
{routesWithoutLayout.map(({ protected, id, path, element }) =>
protected ? (
<Route key={id} element={<ProtectedRoute />}>
<Route path={path} element={element} />
</Route>
) : (
<Route key={id} path={path} element={element} />
)
)}
<Route element={<Layout />}>
{appRoutes.map(({ protected, id, path, element }) =>
protected ? (
<Route key={id} element={<ProtectedRoute />}>
<Route path={path} element={element} />
</Route>
) : (
<Route key={id} path={path} element={element} />
)
)}
</Route>
<Route path='*' element={<p>Page not found</p>} />
</Routes>
);

Or conditionally render a route with the PrivateRoute or Outlet as the element.

const NavigationRoutes = () => (
<Routes>
{routesWithoutLayout.map(({ protected, id, path, element }) => {
const LayoutWrapper = protected ? ProtectedRoute : Outlet;
return (
<Route key={id} element={<LayoutWrapper />}>
<Route path={path} element={element} />
</Route>
);
})}
<Route element={<Layout />}>
{appRoutes.map(({ protected, id, path, element }) => {
const LayoutWrapper = protected ? ProtectedRoute : Outlet;
return (
<Route key={id} element={<LayoutWrapper />}>
<Route path={path} element={element} />
</Route>
);
})}
</Route>
<Route path='*' element={<p>Page not found</p>} />
</Routes>
);

Using wrapper components and the children prop

The code could also be simplified by rendering the ProtectedRoute as a wrapper component instead of a layout route component. This utilizes the children prop instead of using the Outlet component.

Example:

const NavigationRoutes = () => (
<Routes>
{routesWithoutLayout.map(({ protected, id, path, element }) => {
const Wrapper = protected ? ProtectedRoute : React.Fragment;
return (
<Route
key={id}
path={path}
element={<Wrapper>{element}</Wrapper>}
/>
);
})}
<Route element={<Layout />}>
{appRoutes.map(({ protected, id, path, element }) => {
const Wrapper = protected ? ProtectedRoute : React.Fragment;
return (
<Route
key={id}
path={path}
element={<Wrapper>{element}</Wrapper>}
/>
);
})}
</Route>
<Route path='*' element={<p>Page not found</p>} />
</Routes>
);

Reduce further by moving the protected condition into the ProtectedRoute and handle the conditional rendering of the element.

const ProtectedRoute = ({ children, protected }) => {
const isAuthenticated = localStorage.getItem('SOME-TOKEN');

if (!protected || isAuthenticated) {
return children || <Outlet />;
}
return <Navigate replace to='/login' />;
};

...

const NavigationRoutes = () => (
<Routes>
{routesWithoutLayout.map(({ protected, id, path, element }) => (
<Route
key={id}
path={path}
element={<ProtectedRoute {...{ protected }}>{element}</ProtectedRoute>}
/>
))}
<Route element={<Layout />}>
{appRoutes.map(({ protected, id, path, element }) => (
<Route
key={id}
path={path}
element={<ProtectedRoute {...{ protected }}>{element}</ProtectedRoute>}
/>
))}
</Route>
<Route path='*' element={<p>Page not found</p>} />
</Routes>
);

Use an improved routes configuration object and the useRoutes hook

Resturcture the routes config to more closely match what/how you want to render the routes and use the useRoutes hook

Example:

export const appRoutes = [
{
// routes with Layout
element: <Layout />,
children: [
{
// protected routes
element: <ProtectedRoute />,
children: [
{
path: '/protected',
element: <ProtectedPage />,
},
... other protected routes inside Layout
],
},
// unprotected routes
{
path: '/',
element: <Home />,
},
... other unprotected routes inside Layout
],
},
// routes w/o Layout
{
// protected routes
element: <ProtectedRoute />,
children: [
{
path: '/signup',
element: <Signup />,
},
... other protected routes outside Layout
],
},
// unprotected routes
{
path: '/login',
element: <Login />,
},
... other unprotected routes outside Layout
];

NavigationRoutes

import { useRoutes } from 'react-router-dom';
import { appRoutes } from './routes';

const NavigationRoutes = () => {
const routes = useRoutes(appRoutes);
return routes;
};

export default NavigationRoutes;


Related Topics



Leave a reply



Submit