React progress bar on page load/route change(both Next js & CRA)
Tags: react, javascript, nextjs, tutorial
Published: 2021-06-14 14:48:00

Last day I was working on a project which I had to add progress bar (Like youtube's) but I couldn't find anything useful on the internet.

So i decided to create my own and wanna share it with you.
Hope it helps!

*//output*
![progress-bar-ata-parvin-ghods](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/the8h7rn8pomx1qz5hr3.gif)
  

**I'm going to start with create-react-app**
```javascript
// Create a new app
npx create-react-app progress-app react-router-dom react-topbar-progress-indicator

// Run the created app
cd progress-app
yarn start

// http://localhost:3000
```
I used **react-topbar-progress-indicator** package but you can use/create your own.

1.**Define your routes in App.js**
(src/App.js)

```javascript
import { BrowserRouter, Switch, Route } from "react-router-dom"

const App = () => {
   return (
      <>
         <BrowserRouter>
            <Switch>
               <Route exact path='/' />
               <Route exact path='/about' />
            </Switch>
         </BrowserRouter>
      </>
   )
}

export default App
```
2.**Let's create some pages components**
(src/pages/Home.js)

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

const Home = () => {
   return (
      <div>
         <h1>Home page</h1>
         <Link to='/about'>About</Link>
      </div>
   )
}

export default Home
```

(src/pages/About.js)
```javascript
import { Link } from "react-router-dom"

const About = () => {
   return (
      <div>
         <h1>About page</h1>
         <Link to='/'>Home</Link>
      </div>
   )
}

export default About
```

3.**Import pages in App.js**
```javascript
const App = () => {
   return (
      <>
         <BrowserRouter>
            <Switch>
               <Route exact path='/' component={Home} />
               <Route exact path='/about' component={About} />
            </Switch>
         </BrowserRouter>
      </>
   )
}
```

4.**Now we will create a component and surround our Routes in it.**
(src/CustomSwitch.js)

```javascript
const CustomSwitch = ({ children }) => {
   return (
      <Switch>
         { children }
      </Switch>
   )
}
```

This will return Routes in Switch Component.
Now out App.js should be look like this

```javascript
const App = () => {
   return (
      <>
         <BrowserRouter>
            <CustomSwitch>
               <Route exact path='/' component={Home} />
               <Route exact path='/about' component={About} />
            </CustomSwitch>
         </BrowserRouter>
      </>
   )
}
```

5.**In our CustomSwitch component**
```javascript
import React, { useEffect, useState } from "react"
import { Switch, useLocation } from "react-router-dom"
import TopBarProgress from "react-topbar-progress-indicator"

const CustomSwitch = ({ children }) => {
   const [progress, setProgress] = useState(false)
   const [prevLoc, setPrevLoc] = useState("")
   const location = useLocation()

   return (
      <>
         {progress && <TopBarProgress />}
         <Switch>{children}</Switch>
      </>
   )
}
```
We use **react-router-dom** location hook. This hook will show us the path.

```javascript
   useEffect(() => {
      setPrevLoc(location.pathname)
      setProgress(true)
      if(location.pathname===prevLoc){
          setPrevLoc('')
      }
   }, [location])

   useEffect(() => {
      setProgress(false)
   }, [prevLoc])
```

Whenever location changed, first useEffect hook will run and change the previous location & set progress bar to **true**.
And whenever previous location changed the second useEffect will run and change progress bar back to **false**.

**Our CustomeSwitch.js should look like this**
(src/CustomSwitch.js)

```javascript
import React, { useEffect, useState } from "react"
import { Switch, useLocation } from "react-router-dom"
import TopBarProgress from "react-topbar-progress-indicator"

const CustomSwitch = ({ children }) => {
   const [progress, setProgress] = useState(false)
   const [prevLoc, setPrevLoc] = useState("")
   const location = useLocation()

   useEffect(() => {
      setPrevLoc(location.pathname)
      setProgress(true)
      if(location.pathname===prevLoc){
          setPrevLoc('')
          //thanks to ankit sahu
      }
   }, [location])

   useEffect(() => {
      setProgress(false)
   }, [prevLoc])

   return (
      <>
         {progress && <TopBarProgress />}
         <Switch>{children}</Switch>
      </>
   )
}

export default CustomSwitch
```

*And your done with create-react-app*

**Let's continue with Next.Js**
This one is actually quite simple than **CRA**

**Create Next app using commands**
```javascript
// Create a new app
npx create-next-app progress-app react-topbar-progress-indicator

// Run the created app
cd progress-app
yarn dev

// http://localhost:3000
```

1.**Add one page**
(pages/about.js)

```javascript
import Link from "next/link"

const About = () => {
   return (
      <div>
         <h1>About page</h1>
         <Link href='/'>
            <a>HOME PAGE</a>
         </Link>
      </div>
   )
}

export default About
```

And your index.js
(pages/index.js)

```javascript
import Link from "next/link"

const Home = () => {
   return (
      <div>
         <h1>Home page</h1>
         <Link href='/about'>
            <a>About PAGE</a>
         </Link>
      </div>
   )
}

export default Home
```

*Now we are ready*

3.**In _app.js**
(pages/_app.js)

```javascript
import Router from "next/router"
import { useState } from "react"

export default function MyApp({ Component, pageProps }) {
   const [progress, setProgress] = useState(false)

   return (
      <Component {...pageProps} />
   )
}
```

Next.Js provide us some functions with Router, which you can read more about it in [Next-JS-Routing](https://nextjs.org/docs/routing/introduction)

```javascript
import Router from "next/router"
import { useState } from "react"
import TopBarProgress from "react-topbar-progress-indicator"


export default function MyApp({ Component, pageProps }) {
   const [progress, setProgress] = useState(false)

   Router.events.on("routeChangeStart", () => {
      setProgress(true) 
      //function will fired when route change started
   })

   Router.events.on("routeChangeComplete", () => {
      setProgress(false) 
      //function will fired when route change ended
   })

   return (
      <>
         {progress && <TopBarProgress />}
         <Component {...pageProps} />
      </>
   )
}
```

When Route changed, state become true and progress bar will be shown and when route changing ended it will disappear.

*You are done my friends!*

I hope you enjoyed this post.