# React Router 6 🚀

## Docs

[React Router Docs](https://reactrouter.com/docs/en/v6/getting-started/overview)

To install react-router-6

```
npm install react-router-dom@6

// For latest version
npm install react-router-dom
```

## First page

```javascript
import { BrowserRouter, Routes, Route } from 'react-router-dom'

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<div>home page</div>} />
        <Route
          path="testing"
          element={
            <div>
              <h2>testing </h2>
            </div>
          }
        />
      </Routes>
    </BrowserRouter>
  )
}

export default App
```

## Components

```javascript
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import Products from './pages/Products'

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
        <Route path="products" element={<Products />} />
      </Routes>
    </BrowserRouter>
  )
}

export default App
```

## Link

If we want to navigate through our app internally, then we use `Link`.  `Link` is similar to `<a href` but is used to open different page in our app and not external URLs like `google.com`

Let's say I am in `Home page,` / and I want to navigate to `About` page, `/about` then we can either type the /about in URL or use Link (when clicked will take us to /about page).

```javascript
import { Link } from 'react-router-dom'

const Home = () => {
  return (
    <section className="section">
      <h2>Home Page</h2>
      <Link to="/about" className="btn">
        About
      </Link>
    </section>
  )
}
export default Home
```

If we need to go to external URLs like google.com, then we still need to use `<a href`

## Error Page

If we navigate to non-existing URL within our app then it shows a blank page by default which is not a good user experience. We can define a wildcard route (\*) which goes to the page we say if none of the above routes match

```javascript
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import Error from './pages/Error'

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
        
        // DEFAULT ROUTE IF ABOVE ROUTES DON'T MATCH
        <Route path="*" element={<Error />} /> 
      </Routes>
    </BrowserRouter>
  )
}

export default App
```

```javascript
import { Link } from 'react-router-dom'

const Error = () => {
  return (
    <section className="section">
      <h1>404</h1>
      <h2>Page not found</h2>
      <Link to="/" className="btn">
        Back Home
      </Link>
    </section>
  )
}
export default Error
```

## Navbar

<figure><img src="/files/OGT9g4UJELnI2xJ106g0" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/EQELH1qt7z57ayhPzkuh" alt=""><figcaption></figcaption></figure>

We want a navbar/ footer that will be common to all the pages (Home, about, and products). We can achieve it by&#x20;

* nesting these routes inside common path. For example, we want all routes to start at /&#x20;
  * /&#x20;
  * /about
  * /products
* Once we nest them, we also need to use outlet section inside main route / so that this `<Outlet/>` will be either Home, Or About or Products

<figure><img src="/files/uCZLeH1bPAnFoSJrkQsZ" alt=""><figcaption><p>App.js</p></figcaption></figure>

<figure><img src="/files/qXmA9rT0hDyEJYL9MEhv" alt=""><figcaption><p>Home.js (Main Page that contains Outlet)</p></figcaption></figure>

<figure><img src="/files/On7RhwW1hOv4csPwoKFt" alt=""><figcaption><p>Navbar (inside Home)</p></figcaption></figure>

Understand this diagrammatically here [#explained-shared-layout-diagrammatically](#explained-shared-layout-diagrammatically "mention")

## NavLinks

We need to know which link is selected, so we often add an active class. We can make use of NavLink provided by `react-router-dom` instead of Link. The difference is, the NavLink will show us if selected link is active or not.

```javascript
import { NavLink } from 'react-router-dom'

<nav className="navbar">
  <NavLink
    to="/about"
    style={({ isActive }) => {
      return { color: isActive ? 'red' : 'grey' }
    }}
  >
    Home
  </NavLink>
</nav>
```

So our Navbar can look like this, let's name it StyledNavbar

{% code title="StyledNavbar.js" %}

```javascript
import React from 'react'
import { NavLink } from 'react-router-dom'

const active = (isActive) => {
  return isActive ? 'link active' : 'link'
}

export const StyledNavbar = () => {
  return (
    <nav className="navbar">
      <NavLink to="/" className={({ isActive }) => active(isActive)}>
        Home
      </NavLink>
      <NavLink className={({ isActive }) => active(isActive)} to="/about">
        About
      </NavLink>
      <NavLink className={({ isActive }) => active(isActive)} to="/products">
        Products
      </NavLink>
      <NavLink className={({ isActive }) => active(isActive)} to="/login">
        Login
      </NavLink>
    </nav>
  )
}
```

{% endcode %}

We can use inline style or className as above.

## URL Params (useParams)

Let's say we have products page that contains a list of products, and when we click on a product it will take us to details of individual product. We can make use of useParam() hook to see dynamically what ID is passed

{% code title="App.js" %}

```javascript
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<SharedLayout />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />} />
          // These two routes below (products and it's id route can also be nested. Will see later how)
          <Route path="products" element={<Products />} />
          
          // this id will be passed as a parameter in url and we can know that id using useParam hook
          <Route path="products/:productId" element={<SingleProduct />} /> 
          <Route path="*" element={<Error />} />
        </Route>
      </Routes>
    </BrowserRouter>
  )
}
```

{% endcode %}

{% code title="Products.js" %}

```javascript
import { Link } from 'react-router-dom'
import products from '../data'
const Products = () => {
  return (
    <section className="section">
      <h2>products</h2>
      <div className="products">
        {products.map((product) => {
          return (
            <article key={product.id}>
              <h5>{product.name}</h5>
              <Link to={`/products/${product.id}`}>more info</Link>
            </article>
          )
        })}
      </div>
    </section>
  )
}

export default Products
```

{% endcode %}

{% code title="SingleProduct.js" %}

```javascript
import { Link, useParams } from 'react-router-dom'
import products from '../data'
const SingleProduct = () => {

  // we get the dynamically passed parameter using useParams()
  const { productId } = useParams()

  return (
    <section className="section product">
      <h2>{productId}</h2>
      <Link to="/products">back to products</Link>
    </section>
  )
}

export default SingleProduct
```

{% endcode %}

## Navigate (useNavigate)

Let's say we have a /login route that displays a login form, and when user logs in by filling creds, it should navigate us to Dashboard page. In Dashboard page, if user entered the creds, it should show "Hello, name", else it should display "Hello"

{% code title="App.js" %}

```javascript
function App() {
  const [user, setUser] = useState(null)

  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<SharedLayout />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />} />
          
          // products and products/:productId could be nested (we will see how to do this later)
          <Route path="products" element={<Products />} />
          <Route path="products/:productId" element={<SingleProduct />} />
          
          <Route path="login" element={<Login setUser={setUser} />} />
          <Route path="dashboard" element={<Dashboard user={user} />} />
          <Route path="*" element={<Error />} />
        </Route>
      </Routes>
    </BrowserRouter>
  )
}
```

{% endcode %}

{% code title="Login.js" %}

```javascript
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
const Login = ({ setUser }) => {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const navigate = useNavigate();

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!name || !email) return;
    setUser({ name: name, email: email });
    navigate('/dashboard');
  };
```

{% endcode %}

{% code title="Dashboard.js" %}

```javascript
const Dashboard = ({ user }) => {
  return (
    <section className="section">
      <h4>Hello, {user?.name}</h4>
    </section>
  )
}
export default Dashboard
```

{% endcode %}

## Protected Route

Let's say we don't want to show the Dashboard page if user is not logged in, then we can protect that route like this

We can use `<Navigate to=""/>` to navigate to any page.&#x20;

Two ways we can navigate to different pages

* `useNavigate()` can be used outside jsx
* `<Naviage/>` can be used inside jsx

{% code title="App.js" %}

```javascript
<Route
  path="dashboard"
  element={
    <ProtectedRoute user={user}>
      <Dashboard user={user} />
    </ProtectedRoute>
  }
/>
```

{% endcode %}

{% code title="ProtectedRoute.js" %}

```javascript
import { Navigate } from 'react-router-dom'

const ProtectedRoute = ({ children, user }) => {
  if (!user) {
    return <Navigate to="/" />
  }
  return children
}

export default ProtectedRoute
```

{% endcode %}

### Shared Layout for Products

We were using this structure for products and :productId[#navigate-usenavigate](#navigate-usenavigate "mention")

```javascript
<Route path="/" element={<SharedLayout />}>
    <Route index element={<Home />} />
    <Route path="about" element={<About />} />
    
    // products and products/:productId could be nested (we will see how to do this later)
    <Route path="products" element={<Products />} />
    <Route path="products/:productId" element={<SingleProduct />} />
    
    <Route path="login" element={<Login setUser={setUser} />} />
    <Route path="dashboard" element={<Dashboard user={user} />} />
    <Route path="*" element={<Error />} />
    </Route>
</Routes>
```

Both of these routes "products" and  "products/:productId" can be turned into nested route so that we know it is a group.

We do this similar to what we did in SharedLayout above.&#x20;

{% code title="SharedProductLayout.js" %}

```javascript
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import SharedLayout from './pages/SharedLayout'
import About from './pages/About'
import Products from './pages/Products'
import SingleProduct from './pages/SingleProduct'
import Login from './pages/Login'
import Dashboard from './pages/Dashboard'
import Home from './pages/Home'
import { useState } from 'react'
import { ProtectedRoute } from './pages/ProtectedRoute'
import SharedProductLayout from './pages/SharedProductLayout'

function App() {
  const [user, setUser] = useState(null)
  console.log('The user now is ', user)
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<SharedLayout />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />} />

          {/* SHARED PRODUCT LAYOUT */}

          <Route path="products" element={<SharedProductLayout />}>
            <Route index element={<Products />} />
            <Route path=":id" element={<SingleProduct />} />
          </Route>

          <Route path="login" element={<Login setUser={setUser} />} />
          <Route
            path="dashboard"
            element={
              <ProtectedRoute user={user}>
                <Dashboard user={user} />
              </ProtectedRoute>
            }
          />
        </Route>
      </Routes>
    </BrowserRouter>
  )
}

export default App
```

{% endcode %}

The  parent SharedProductLayout contains only the placeholder for underlying child components and that placeholder is `<Outlet/>`

```javascript
import { Outlet } from 'react-router-dom'

const SharedProductLayout = () => {
  return (
    <>
      <div className="section">
        <Outlet />
      </div>
    </>
  )
}
export default SharedProductLayout
```

{% code title="SingleProduct.js" %}

```javascript
import { Link, useParams } from 'react-router-dom'
import products from '../data'

const SingleProduct = () => {
  const { id } = useParams()
  const { name, image } = products.find((product) => product.id === id)
  return (
    <section className="section product">
      <h2>{name}</h2>
      <img src={image} alt="product" />
      <br />
      <Link to="/products" className="btn">
        Back to products
      </Link>
    </section>
  )
}

export default SingleProduct
```

{% endcode %}

### Explained  Shared layout diagrammatically

<figure><img src="/files/lr5h3kxSEpDK2NmATNu6" alt=""><figcaption><p>diagrammatically explained shared layout</p></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sandeepamaranath.gitbook.io/notes/languages-and-frameworks/react-router-6.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
