React Router's useRoutes hook
Tags: react, javascript, beginners, programming
Published: 2022-01-13 16:23:11

When creating multi-paged apps with React or any other library/framework, a package to handle routing is always used. Whether it is Vue Router for Vue apps, React Router for React apps, etc. Today I'm going to emphasize implementing routes in React using React Router's useRoutes hook.

## Prerequisites
Although I will try my best to make this easy enough for a beginner to understand, I advise that before going further you at least have basic knowledge of React and have at least seen React Router used in an application. If you have no experience with React Router, you could look at the documentation first. They give really clear examples that will get you up to speed in no time.

## Approach 1: Using the `<Routes>` and `<Route>` JSX components
This is the primary way of rendering something using React Router and the approach that would be seen used in many places. Hence, I won't dwell much on the syntax of this but drop the example which will be used in the rest of this article.

### `MainLayout.js`
This is a layout component for any page that is not an authentication page.

```
import { Link, Outlet } from "react-router-dom";
export default function MainLayout() {
    return (
        <>
            <nav className="nav-bar">
                 <ul>
                     <li>
                         <Link to="home"> Home</Link>
                     </li>
                     <li>
                         <Link to="about"> About</Link>
                     </li>
                     <li>
                         <Link to="/"> Log In</Link>
                     </li>
                     <li>
                         <Link to="signup"> Sign Up</Link>
                     </li>
                 </ul>
            </nav>
            <Outlet />
        </>
    );
}
```

### `Home.js`
```
export default function Home() {
    return (
        <div className="App">
            <h1>Home Page</h1>
        </div>
    );
}
```

The other pages used in this example were defined in a similar way as **`Home.js`**. You can look at the sandbox to see them for clarity. These however form the main elements of the example.

### `App.js`
```
import "./styles.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from './pages/Home'
import About from './pages/About'
import Login from './pages/Login'
import SignUp from './pages/Signup'
import AuthLayout from './layouts/AuthLayout'
import MainLayout from './layouts/MainLayout'

export default function App() {
    return (
        <BrowserRouter>
            <div className="App">
                <h1>React Router Example</h1>
                <Routes>
                    <Route element={<AuthLayout/>}>
                        <Route path="/" element={<Login/>}/>
                        <Route path="signup" element={<SignUp />}/>
                    </Route>
                    <Route element={<MainLayout/>}>
                        <Route path="home" element={<Home/>}/>
                        <Route path="about" element={<About />}/
                    </Route>
                </Routes>
             </div>
        </BrowserRouter>
     );
}
```
{% codesandbox optimistic-bhabha-vmdk2 %}

You can read more about this in React Router documentation here. The **`<Routes>`** component acts as a wrapper for all possible routes that can be matched. The **`<Route>`**  carries an element in its element attribute. If the content of its path attribute matches the current URL, it renders the content of the element attribute. As location changes a user navigates the app, the corresponding elements are rendered.
To make this example as comprehensive as possible, I took the routing from a side project I am working on and it has one kind of route which won't be in a basic example of routes - Layout Routes. A layout route is a parent route without a path attribute used to group child routes under a specific layout. For more on this and other major concepts of React Router have a look at this part of the documentation. It's a bit lengthy but it will get you up-to-speed with the lingo quickly.

## Approach 2: Using the useRoutes hook

### `routes.js`
```
import { useRoutes } from "react-router-dom";
import Home from './pages/Home'
import About from './pages/About'
import Login from './pages/Login'
import SignUp from './pages/Signup'
import AuthLayout from './layouts/AuthLayout'
import MainLayout from './layouts/MainLayout'

export default function Router() {
let element = useRoutes([
    {
        element: <AuthLayout />,
        children: [
           { path: "/", element: <Login /> },
           { path: "signup", element: <SignUp /> },
        ],
    },
    {
        element: <MainLayout />,
        children: [
            { path: "home", element: <Home /> },
            { path: "about", element: <About /> },
        ],
    },
]);
return element;
}
```
### `App.js`
```
import "./styles.css";
import { BrowserRouter } from "react-router-dom";
import Router from './routes'

export default function App() {
return (
    <BrowserRouter>
        <div className="App">
            <h1>useRoutes Example</h1>
            <Router/>
        </div>
    </BrowserRouter>
);
}
```
The other components are defined the same way as in the previous approach. You can look at the sandbox below to see it all in one cohesive example.

{% codesandbox thirsty-architecture-jgok5 %}

Note that for clarity and separation of concerns in writing code, I do not declare the object-based config in the same file as to where I want to use the routes. In my project, I created a folder called **`routes`** and a file called **`index.js`** to hold the routes. Another common convention I have seen devs do is to create a file in the **`src`** folder called **`routes.js`** and put it all there.

![Routes file in routes folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/371szz3cg7hn3ggtib3t.png)

![routes.js file in the `src` folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ni4eusgzcz2vz0v51giw.png)

So let's look closer at what is happening in the `**routes**` file. The routes are inserted as objects in an array, with each object representing one route. The object has keys and values similar to the attributes and values of the **`<Route>`** component. To account for nested routes, the object has an optional third key known as **`children`** that allows you to list all child routes of a specific route. The nesting can go as deep as your application requires it to be. 

![Nested routing in useRoutes hook](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tzy9sku5yhdpo76pta19.png)

The return value of the `**useRoutes**` hook is either a valid React element or `**null**` if nothing matched. Once you are done creating the routes, you then add them to your app in the same place you would have added the `**<Routes>**` and `**<Route>**` components which for me is my `**App.js**` file:

![adding routes from routes.js to App.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78t3p63ycyvqtvi2f5k1.png)

The **`routes.js`** file is imported in **`App.js`** and added just as you would any other component. It was created in a functional component, after all. Remember that hooks can't be used outside of functions and that is why it was declared inside of one. If I intended to use it in **`App.js`**, I would've declared it inside the function as well.

There aren't any clear benefits of using one approach of routing over another, it all depends on the preference of the developer or team and the use case. For me, abstracting the route config using the hook made it easier for me to understand and anyone visiting my project.

## Resources
For a closer look at the code used in this article, you can visit these two sandboxes;

[useRoutes Example](https://codesandbox.io/s/thirsty-architecture-jgok5?file=/src/App.js:0-289)

[Routes JSX Example](https://codesandbox.io/s/optimistic-bhabha-vmdk2.)