In this article, we will get to know about What is the Index route, dynamic routes with react-router, and nested dynamic routes.

In the previous article, we learned about nested routes with React routers. we have the products page which consists of two nested routes

  • featured which renders the list of featured products and 
  • new which renders the list of new products
Dynamic Routes


However, you might have noticed that the child routes render only when the URL is

/products/featured or /products/new

What is an index route?

But sometimes you might want one of the child routes to render at the parent route level that is if we navigate to just products and the URL reads /products, we might still want to display the list of featured products

Now that can be achieved using what is called an index route in React router

let's see an example of index route,

The index route is also going to be a nested route so within the products route, add a new route component. 


import { Component } from 'react'
import { Routes, Route } from 'react-router-dom'
import { FeaturedProducts } from './components/FeaturedProducts';
import { NewProducts } from './components/NewProducts';
import { OrderSummary } from './components/OrderSummary';
import { PageNotFound } from './components/PageNotFound';
import { Products } from './components/Products';

import Welcome from './components/Welcome'

function App() {
return (
<Routes>
<Route path="/" element={<Welcome />} />
<Route path="contact" element={<Component />} />
<Route path="order-summary" element={<OrderSummary />} />
<Route path="products" element={<Products />} >
<Route index element={<FeaturedProducts />} />
<Route path="featured" element={<FeaturedProducts />} />
<Route path="new" element={<NewProducts />} />
</Route>
<Route path="*" element={<PageNotFound />} />
</Routes>
);
}

export default App;

what is special here though is we don't specify the path prop instead we specify a prop called index this index route will now share the path of the parent route which is products, finally we specify the element prop just like the other routes since we want the featured products to be rendered the element is going to be the FeaturedProducts component.


if you now head back to the browser and navigate to the products page the URL is just /products but we still see the featured products child component, of course, if you click on featured it remains the same and you can also navigate to new products,  but you can see the index route is working as expected.



So when you have nested routes and you want a route to be rendered at the parent URL make use of an index route, the index route will contain the index prop instead of the path prop, the path would be the same as the parent route.


Dynamic routes with React router?

Let's assume we are building an admin dashboard and we need a user listing and details page. If the user navigates to /users, we should display a list of three users

However in addition to this, if the user navigates to slash users followed by the id of that user,  we need to display details about that individual user.

For example, if the user navigates to /users/1, we should display details about the first user.

Similarly, if the user navigates to /users/2 we need to display details about the second user, in /users/3 we need to display details about the  third user 

let's understand how to achieve this with React router 

Let me create a new file in the components folder  users.js, within the file let's define a component  that displays a list of three users 

Users.js

import React from 'react'

export const Users = () => {
return (
<div>
<h2> User 1</h2>
<h2> User 2</h2>
<h2> User 3</h2>

</div>
)
}

Now let's configure a route for this component in app.js, add a new route  where the path prop is going to be equal  to users and the element is going to be  equal to the user's component that we  have just defined  make sure to import the component at the  top 

App.js


import { Component } from 'react'
import { Routes, Route } from 'react-router-dom'
import { Users } from './components/Users'

function App() {
return (
<Routes>
<Route path="users" element={<Users />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
);
}

export default App;

if you now head back to the browser  and type in localhost:3000/users, we see the list of users as expected 



Our listing page has been implemented.


Next, let's focus on the details page, we know that we need a detailed view for the user, so let's create a new component within the components folder a new file  called user userdetails.js 

UserDetails.js

import React from 'react'

export const UserDetails = () => {
return (
<div>
Details about user
</div>
)
}

within the file, I'm going to create a component that renders the text details about the user and this same component has to be rendered for three different URLs 

/users/1 

/users/2

/users/3


let's add the routes in app.js,


import { Component } from 'react'
import { Routes, Route } from 'react-router-dom'
import { UserDetails } from './components/UserDetails';
import { Users } from './components/Users';


function App() {
return (
<Routes>
<Route path="users" element={<Users />} />
<Route path="users/:userId" element={<UserDetails />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
);
}

export default App;

The correct solution is to. implement this functionality,  use dynamic route segments, for our scenario the userId which can be 1, 2, 3, and so on. It should be a dynamic value and for such a value we specify what is termed as a URL param in React router  

So instead of users/1,  we specify users/:userId.  This userId param will match any value as long as the pattern is the same that is the URL in the browser is /users/{any value}.

If we head back to the browser and navigate to /users/1, we see the user details page. It works for /2, /3, and even /100.  So when you have to work with list and detail routes,  dynamic routes are what you need.

Now there is one point that I would like you to make note of, the userId can be any string and not just a number, so in the browser, I could type /users/admin  and it would render the same page 

So in the components folder, I'm going to  create a new file called admin.js,  within the file I'm going to define and  export a simple component  the component name is admin  and we're going to return some text  admin user  

Admin.js

import React from 'react'

export const Admin = () => {
return (
<div>
Admin user
</div>
)
}

In the routes config, I'm going to add another route  

<Route path="users/admin" element={<Admin />} />

route  path is equal to  users slash admin  and element is going to be equal to the  admin component, we have just defined,  make sure to import the component at the  top  


import { Component } from 'react'
import { Routes, Route } from 'react-router-dom'
import { Admin } from './components/Admin';
import { UserDetails } from './components/UserDetails';
import { Users } from './components/Users';

import Welcome from './components/Welcome'

function App() {
return (
<Routes>

<Route path="users" element={<Users />} />
<Route path="users/:userId" element={<UserDetails />} />
<Route path="users/admin" element={<Admin />} />
<Route path="*" element={<PageNotFound />} />
</Routes>
);
}

export default App;

The question to you is if we navigate to users/admin,  will the user details page be rendered or the admin page render?

Let's head to the browser and find out so localhost:3000/users/admin and you can see that the admin component is rendered.  This is something I want you to keep in mind.

Even though we have a dynamic route where the userId can be anything,  React router is smart enough to first match the route that is more specific. So if you navigate to users/admin, the React router will first try to find a matching route only, if that is not found will it match the dynamic route.

Nested Dynamic Routes?

All right the last bit I want to mention  here is that dynamic routes can be nested as well 

Since the two routes we have just configured have users as the prefix  we can nest them  of course the child component would be  rendered within the parent component 

So the user's parent route will now have opening and closing tags and the two routes are nested inside from the path prop though we need to remove users 

App.js


import { Component } from 'react'
import { Routes, Route } from 'react-router-dom'
import { Admin } from './components/Admin';
import { UserDetails } from './components/UserDetails';
import { Users } from './components/Users';

function App() {
return (
<Routes>
<Route path="users" element={<Users />} >
<Route path=":userId" element={<UserDetails />} />
<Route path="admin" element={<Admin />} />
</Route>

<Route path="*" element={<PageNotFound />} />
</Routes>
);
}

export default App;

Finally, in the user's component, we need to add the outlet component for  rendering the child  

so import  outlet from react-router-dom  and invoke it below the list of users 

Users.js

import React from 'react'
import { Outlet } from 'react-router-dom'
export const Users = () => {
return (
<div>
<h2> User 1</h2>
<h2> User 2</h2>
<h2> User 3</h2>
<Outlet />
</div>
)
}

Take a look at the browser  and our nested dynamic route is working  as expected  

Alright,  let me quickly summarize the  takeaway points from this article  

First when dealing with a list detail  pattern or if the route parameter can  vary in value make use of dynamic routes  specify the URL param denoted by a colon  prefix in the path  

Second point react-router will always  try to match the route that is more  specific before trying to match a  dynamic route  so slash admin before slash userId  

Third, it is possible to have nested  dynamic routes  

Hopefully, this video has given you a  good amount of information on dynamic  routes 


Here is the link to know more about React routes