Page navigation with react-router-dom
Tags: webdev, react, navigation
Published: 2024-06-30 14:31:00

To navigate to pages in a React project, we use react-router-dom, which offers many features such as routing and creating layouts with <Outlet/>, etc. Today, I'd like to show you how to use react-router-dom in a React project with Vite.

I recommend you read my article on setting up a React project [here](https://dev.to/thinhkhang97/react-vite-tailwind-project-57pf) before getting started.

## Installation
```bash
npm install react-router-dom
```

## Preparation

First, we need to imagine the project we're going to build. This project will list Pokémon data, as shown in the image below. It has several pages:

* /home: Landing page
* /pokemons: Pokémon list
* /pokemons/:id Pokémon detail
* /favorites: All your favorite Pokémon

![/pokemons page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yqv6kkw12lylc9mfq91s.png)

Below is the project structure
```css
src/
├── apis/
│   ├── index.ts
│   └── pokemons.ts
├── assets/
│   └── logo.svg
├── components/
│   ├── index.ts
│   └── navbar.tsx
├── pages/
│   ├── favorites/
│   │   └── page.tsx
│   ├── home/
│   │   ├── components/
│   │   └── page.tsx
│   ├── not-found/
│   │   └── page.tsx
│   ├── pokemon/
│   │   └── page.tsx
│   └── pokemons/
│       ├── components/
│       ├── index.ts
│       └── layout.tsx
├── types/
│   ├── index.ts
│   ├── pokemon.ts
├── app.tsx
├── index.css
├── main.tsx
└── vite-env.d.ts
.env
```

## Configuring Routing

To enable client-side routing in this React application, we need to wrap entire application in `<BrowserRouter>` component. For each page, we need to create a `<Route/>` component, example for path `/favorites`, we get this 

```tsx
<Route path="/favorites" element={<FavoritesPage />} />
```

As you can see, we have a `navbar` component that we want to keep at the top of these pages. So I created a layout named MainLayout which includes an `<Outlet/>` component to help us switch page content while keeping the `navbar` fixed.

```tsx
import { Outlet } from "react-router-dom";
import { Navbar } from "../components";

export default function MainLayout() {
  return (
    <div>
      <Navbar />
      <Outlet />
    </div>
  );
}
```

Then we need to make all the pages have the same layout (with the `navbar` on top) and only change the content nested inside the `MainLayout` route. From now on, each time you access to the path `/pokemons` or `/favorites`, the client will just change the content inside the layout and keep the `navbar` component.

```tsx
export default function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<MainLayout />}>
          <Route path="/" element={<HomePage />} />
          <Route path="/favorites" element={<FavoritesPage />} />
          <Route path="/pokemons" element={<PokemonsPage />} />
          <Route path="/pokemons/:id" element={<PokemonPage />} />
        </Route>
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}
```

## Get params
When working with `react-router-dom`, you might have trouble getting params of the path. For example `/pokemons/:id`, you need to get the `id` value to fetch data of a Pokemon by its id in `PokemonPage`. 

You can use `useParams` hook to get it like this
```tsx
const { id } = useParams();
```

The hook returns an object that contains all params that appear in the URL. Now you can take the id to get the Pokemon data.

That's it for the article, I hope it can help you to set up a project with `react-router-dom`. If you have any comments or suggestions, please let me know, I'd love to hear them. Thanks for reading