DEV Community

loading...

React progress bar on page load/route change(both Next js & CRA)

Ata Parvin Ghods
Tengri biz menen
Updated on ・3 min read

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

I'm going to start with create-react-app

// 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
Enter fullscreen mode Exit fullscreen mode

I used react-topbar-progress-indicator package but you can use/create your own.

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

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
Enter fullscreen mode Exit fullscreen mode

2.Let's create some pages components
(src/pages/Home.js)

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

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

export default Home
Enter fullscreen mode Exit fullscreen mode

(src/pages/About.js)

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

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

export default About
Enter fullscreen mode Exit fullscreen mode

3.Import pages in App.js

const App = () => {
   return (
      <>
         <BrowserRouter>
            <Switch>
               <Route exact path='/' component={Home} />
               <Route exact path='/about' component={About} />
            </Switch>
         </BrowserRouter>
      </>
   )
}
Enter fullscreen mode Exit fullscreen mode

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

const CustomSwitch = ({ children }) => {
   return (
      <Switch>
         { children }
      </Switch>
   )
}
Enter fullscreen mode Exit fullscreen mode

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

const App = () => {
   return (
      <>
         <BrowserRouter>
            <CustomSwitch>
               <Route exact path='/' component={Home} />
               <Route exact path='/about' component={About} />
            </CustomSwitch>
         </BrowserRouter>
      </>
   )
}
Enter fullscreen mode Exit fullscreen mode

5.In our CustomSwitch component

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>
      </>
   )
}
Enter fullscreen mode Exit fullscreen mode

We use react-router-dom location hook. This hook will show us the path.

   useEffect(() => {
      setPrevLoc(location.pathname)
      setProgress(true)
   }, [location])

   useEffect(() => {
      setProgress(false)
   }, [prevLoc])
Enter fullscreen mode Exit fullscreen mode

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)

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)
   }, [location])

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

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

export default CustomSwitch
Enter fullscreen mode Exit fullscreen mode

And your done with create-react-app

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

Create Next app using commands

// 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
Enter fullscreen mode Exit fullscreen mode

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

import Link from "next/link"

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

export default About
Enter fullscreen mode Exit fullscreen mode

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

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
Enter fullscreen mode Exit fullscreen mode

Now we are ready

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

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

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

   return (
      <Component {...pageProps} />
   )
}
Enter fullscreen mode Exit fullscreen mode

Next.Js provide us some functions with Router, which you can read more about it in Next-JS-Routing

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} />
      </>
   )
}
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (2)

Collapse
lordvic4real profile image
lordvic4real • Edited

thank you so much, it worked, so straight forward, for the most basic learner to graps... please how do i include spinner at the top right edge of the progress bar

Collapse
ataparvinghods profile image
Ata Parvin Ghods Author • Edited

Thank you so much. Glad you like it. I didn't get exactly what you want about spinner? If you want spinner instead of progress bar you can change it in the component and add spinner component (instead of TopBarProgress add Spinner ) .