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
Template String as Object Property Name
Referencing "This" Inside Setinterval/Settimeout Within Object Prototype Methods
What Is Returned from a Constructor
How to Execute Promises Sequentially, Passing the Parameters from an Array
Caching a Promise Object in Angularjs Service
Recursive Matching with Regular Expressions in JavaScript
Variable Scope in D3 JavaScript
Chrome Extension - Sendresponse Not Waiting for Async Function
Why Does This JavaScript Code Print "Undefined" on the Console
Turning Off Eslint Rule for a Specific Line
Print Content of JavaScript Object
What's the Best Way to Break from Nested Loops in JavaScript
Ajax Mailchimp Signup Form Integration
Detecting iOS/Android Operating System
How to Limit Google Autocomplete Results to City and Country Only