Last updated: Apr 7, 2024
Reading time·4 min
<Route>
component<Route>
componentThe "[Component] is not a <Route>
component. All component children of
<Routes>
must be a <Route>
or <React.Fragment>
" most commonly occurs
when we use a component as a child of a Route
component.
To solve the error, use the element
prop instead.
Here is the complete error stack trace.
Uncaught Error: [Component] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment> at invariant (history.ts:480:1) at components.tsx:582:1 at react.development.js:1195:1 at react.development.js:1158:1 at mapIntoArray (react.development.js:1049:1) at mapChildren (react.development.js:1157:1) at Object.forEachChildren [as forEach] (react.development.js:1194:1) at createRoutesFromChildren (components.tsx:566:1) at components.tsx:615:1 at react.development.js:1195:1
Here is an example of how the error occurs.
// ⛔️ Uncaught Error: [About] is not a <Route> component. <Route path="/"> <About /> </Route>
Notice that the <About />
component is passed as a child to the Route
component.
Instead, you should use the element
prop to specify which component should be
rendered when the given path is matched.
// ✅ Correct <Route path="/about" element={<About />} /> <Route path="/" element={<Home />} />
You can also pass nested components to the element
prop.
<Route path="/" element={ <ProtectedRoute user={user}> <Home /> </ProtectedRoute> } />
Only Route
or React.Fragment
components are valid children of the Routes
component.
The main reason for this change is that the <Route><Children/></Route>
syntax
is now reserved for nesting routes.
You can read more about the rationale in this section of the React Router docs.
Here is the complete, working component.
import {Route, Link, Routes, BrowserRouter} from 'react-router-dom'; function App() { return ( <BrowserRouter> <div> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <Routes> <Route path="/about" element={<About />} /> <Route path="/" element={<Home />} /> </Routes> </div> </BrowserRouter> ); } function Home() { return <h2>Home Content</h2>; } function About() { return <h2>About Content</h2>; } export default App;
Make sure to not wrap your Router inside another Router.
In some cases, you might want to wrap your Route
components into another
component to apply styling.
For example, assume you have to wrap multiple components in a container
class.
import { Outlet } from 'react-router-dom'; function Dashboard() { return ( <div className='container'> <h1>Dashboard</h1> <Outlet /> </div> ); }
The Outlet component is used in a parent route to render their child route elements.
Let's assume your App
component looks as follows.
function App() { return ( <Routes> <Route path="/" element={<Dashboard />}> <Route path="messages" element={<DashboardMessages />} /> <Route path="tasks" element={<DashboardTasks />} /> </Route> </Routes> ); }
We used an Outlet
component to render the child route elements of the
Dashboard
Route.
The Outlet
component will render:
<DashboardMessages/>
component when the URL is /messages
<DashboardTasks />
component when the URL is /tasks
.null
when the URL is /
.Note that you should no longer pass the exact
prop to Route
components.
The following line causes an error when using React.js with TypeScript.
// ⛔️ Property 'exact' does not exist on type <Route exact path="/" element={<Home />} />
Instead, remove the exact
prop.
// ✅ Correct <Route path="/" element={<Home />} />
The default behavior of Route paths is to match exactly.
If you want to match more of the URL because your component contains nested
routes, use a trailing asterisk /*
in the path.
// ✅ Correct <Route path="/products/*" element={<Products />} />
Now your Products
component might contain nested routes.
function Products() { return ( <div> <nav> <Link to="/">All Products</Link> </nav> <Routes> <Route path="/" element={<ProductsList />} /> <Route path=":id" element={<SpecificProduct />} /> </Routes> </div> ) }
The <Link to>
and Route path
values are automatically scoped to the
/products
URL prefix because the Products
component is only rendered when
the URL matches /products/*
.
If you need to get the ID from a URL in React Router, click on the link and follow the instructions.
You can use the following approach if you need to handle Private/Protected Routes.
import {Navigate, useLocation} from 'react-router-dom' export function RequireAuth({ children }) { const isAuthenticated = false; // your logic here const location = useLocation(); if (!isAuthenticated) { return <Navigate to="/login" state={{ from: location }} />; } return children; }
If the user is not authenticated, we redirect
them to the /login
page.
The location of where they were trying to navigate before getting redirected is
saved using the state
prop.
We can use this location to redirect them to a specific page, rather than a
generic page, such as /
.
Then you would use the RequireAuth
component as follows.
import {Route} from 'react-router-dom' import {RequireAuth} from './RequireAuth' <Route path="/protected" element={ <RequireAuth> <ProtectedPage /> </RequireAuth> } />
An alternative approach is to use the Outlet
component.
import {Outlet, Navigate} from 'react-router-dom'; export const PrivateRoute = () => { const isAuth = null; // Your logic here return isAuth ? <Outlet /> : <Navigate to="/login" />; }
The Outlet component is used in a parent route to render their child route elements.
If the user is authenticated, then the Outlet
component renders its child
route elements.
Otherwise, the user gets redirected to the /login
page.
Here is how you would use the PrivateRoute
component.
import {Routes, Route} from 'react-router-dom'; import {PrivateRoute} from './PrivateRoute' // ... <Routes> <Route path='/' element={<PrivateRoute/>}> {/* Specify private routes here */} <Route path='/' element={<Home/>}/> <Route path='/change-password' element={<ChangePassword/>}/> </Route> {/* Specify public routes here */} <Route path='/register' element={<Register/>}/> <Route path='/login' element={<Login/>}/> </Routes>
Notice that we nest the private routes inside the Route
that has
PrivateRoute
as its element.
Outlet
component is used in a parent route to render their child route elements.In other words, if the user tries to access /
:
PrivateRoute
component checks if the user is authenticated.<Home />
component is rendered./login
page.If the user tries to navigate to /change-password
:
PrivateRoute
component checks if the user is authenticated.<ChangePassword />
component is rendered./login
.