React Router: [Component] is not a <Route> component [Fixed]

avatar
Borislav Hadzhiev

Last updated: Apr 7, 2024
4 min

banner

# Table of Contents

  1. React Router: [Component] is not a <Route> component
  2. Wrapping Route components in a Parent
  3. Property 'exact' does not exist on type in React Router DOM
  4. Creating Private or Protected Route components

# React Router: [Component] is not a <Route> component

The "[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.

component is not a route component

Here is the complete error stack trace.

shell
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.

App.js
// ⛔️ 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.

App.js
// ✅ Correct <Route path="/about" element={<About />} /> <Route path="/" element={<Home />} />
The code for this article is available on GitHub

You can also pass nested components to the element prop.

App.js
<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.

App.js
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;

react router demo

The code for this article is available on GitHub

Make sure to not wrap your Router inside another Router.

# Wrapping Route components in a Parent

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.

App.js
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.

App.js
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:

  • the <DashboardMessages/> component when the URL is /messages
  • the <DashboardTasks /> component when the URL is /tasks.
  • null when the URL is /.

# Property 'exact' does not exist on type in React Router DOM

Note that you should no longer pass the exact prop to Route components.

property exact does not exist on type

The following line causes an error when using React.js with TypeScript.

App.tsx
// ⛔️ Property 'exact' does not exist on type <Route exact path="/" element={<Home />} />

Instead, remove the exact prop.

App.tsx
// ✅ Correct <Route path="/" element={<Home />} />
The code for this article is available on GitHub

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.

App.tsx
// ✅ Correct <Route path="/products/*" element={<Products />} />

Now your Products component might contain nested routes.

App.js
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.

# Creating Private or Protected Route components

You can use the following approach if you need to handle Private/Protected Routes.

RequireAuth.js
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; }
The code for this article is available on GitHub

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.

App.js
import {Route} from 'react-router-dom' import {RequireAuth} from './RequireAuth' <Route path="/protected" element={ <RequireAuth> <ProtectedPage /> </RequireAuth> } />

# Using an alternative approach for Protected Pages

An alternative approach is to use the Outlet component.

PrivateRoute.js
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.

App.js
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>
The code for this article is available on GitHub

Notice that we nest the private routes inside the Route that has PrivateRoute as its element.

This works because the Outlet component is used in a parent route to render their child route elements.

In other words, if the user tries to access /:

  1. The PrivateRoute component checks if the user is authenticated.
  2. if they are, the <Home /> component is rendered.
  3. if they aren't, they get redirected to the /login page.

If the user tries to navigate to /change-password:

  1. The PrivateRoute component checks if the user is authenticated.
  2. If they are, the <ChangePassword /> component is rendered.
  3. If they aren't, the user gets redirected to /login.
I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.