Adding Top Loading Bar And React Router Dom In News App

Posted on July 16, 2026 by Vishesh Namdev
Python C C++ Javascript React JS
Adding Top Loading Bar & React Router DOM in News App - React JS Tutorial for Beginners

Adding Top Loading Bar & React Router DOM in Our News App 🚦🧭 So far our News App shows one category of articles on a single page, with a spinner that appears while we "fetch" data. In this React JS tutorial for beginners, we'll take our project a big step forward by adding a slim top loading bar (like the one you see on YouTube or GitHub) for a more polished loading experience, and by using React Router DOM to create separate routes for each news category — Business, Entertainment, General, Health, Science, Sports, and Technology.

In this tutorial, we will learn:

  • What React Router DOM is and why single page apps need it
  • Installing react-router-dom and react-top-loading-bar
  • Setting up BrowserRouter, Routes, and Route in App.js
  • Creating category-based routes for the News App
  • Building a Navbar component with NavLink
  • Controlling a top loading bar using a ref from a child component
  • Triggering the loading bar during pagination and category changes
  • ---

    What is React Router DOM?

    React Router DOM is the standard library for handling navigation in React applications. It lets us map different URLs to different components, so users can visit /business or /sports and see the matching news category — without a full page reload. This is what makes React apps feel like real multi-page websites while staying fast and smooth as a Single Page Application (SPA).

    ---

    What is a Top Loading Bar?

    A top loading bar is that thin, colored progress bar that slides across the very top of the screen while content is loading. It's a subtle but powerful UX pattern used by sites like YouTube and GitHub — it tells users "something is happening" without blocking the whole screen the way a spinner does.

    ---

    Step 1: Install the Required Packages

    Open your terminal in the project folder and install react-router-dom for routing and react-top-loading-bar for the progress bar.

    npm install react-router-dom react-top-loading-bar
    ---

    Step 2: Wrap the App with BrowserRouter

    Open index.js and wrap the <App /> component with BrowserRouter so routing works throughout the whole application.

    import React from "react";
    import ReactDOM from "react-dom/client";
    import { BrowserRouter } from "react-router-dom";
    import App from "./App";
     
    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render(
      <BrowserRouter>
        <App />
      </BrowserRouter>
    );
    ---

    Step 3: Build a Navbar Component

    Let's create a Navbar.js component using NavLink so users can jump between news categories. NavLink automatically highlights the active route.

    import React from "react";
    import { NavLink } from "react-router-dom";
     
    const Navbar = () => {
      return (
        <nav className="navbar navbar-expand-lg navbar-dark bg-dark">
          <div className="container-fluid">
            <NavLink className="navbar-brand" to="/">
              News App
            </NavLink>
            <div className="collapse navbar-collapse">
              <ul className="navbar-nav ms-auto">
                {["business", "entertainment", "general", "health", "science", "sports", "technology"].map(
                  (category) => (
                    <li className="nav-item" key={category}>
                      <NavLink
                        className="nav-link text-capitalize"
                        to={`/${category}`}
                      >
                        {category}
                      </NavLink>
                    </li>
                  )
                )}
              </ul>
            </div>
          </div>
        </nav>
      );
    };
     
    export default Navbar;
    ---

    Step 4: Define Category Routes in App.js

    Now let's set up Routes and Route in App.js, rendering a News component for each category with a different category prop.

    import React, { Component, createRef } from "react";
    import { Routes, Route } from "react-router-dom";
    import LoadingBar from "react-top-loading-bar";
    import Navbar from "./Navbar";
    import News from "./News";
     
    export default class App extends Component {
     
      state = {
        progress: 0,
      };
     
      topLoadingBarRef = createRef();
     
      render() {
        return (
          <div>
            <LoadingBar
              color="#f11946"
              ref={this.topLoadingBarRef}
              height={3}
            />
            <Navbar />
            <Routes>
              <Route
                path="/"
                element={<News topLoadingBarRef={this.topLoadingBarRef} category="general" />}
              />
              <Route
                path="/business"
                element={<News topLoadingBarRef={this.topLoadingBarRef} category="business" />}
              />
              <Route
                path="/entertainment"
                element={<News topLoadingBarRef={this.topLoadingBarRef} category="entertainment" />}
              />
              <Route
                path="/health"
                element={<News topLoadingBarRef={this.topLoadingBarRef} category="health" />}
              />
              <Route
                path="/science"
                element={<News topLoadingBarRef={this.topLoadingBarRef} category="science" />}
              />
              <Route
                path="/sports"
                element={<News topLoadingBarRef={this.topLoadingBarRef} category="sports" />}
              />
              <Route
                path="/technology"
                element={<News topLoadingBarRef={this.topLoadingBarRef} category="technology" />}
              />
            </Routes>
          </div>
        );
      }
    }
    ---

    Step 5: Control the Loading Bar from News.js

    We pass topLoadingBarRef into our News component as a prop. Inside fetchArticles, we call continuousStart() when a "fetch" begins and complete() when it finishes — this drives the progress bar animation.

    fetchArticles = () => {
      this.props.topLoadingBarRef.current.continuousStart();
      this.setState({ loading: true });
     
      setTimeout(() => {
        this.setState({ loading: false });
        this.props.topLoadingBarRef.current.complete();
      }, 1000);
    };
    ---

    Step 6: Full Updated News.js

    Here is News.js updated to accept a category prop from the route and to drive the top loading bar alongside the existing spinner and pagination logic.

    import React, { Component } from "react";
    import NewsItem from "./NewsItem";
    import Spinner from "./Spinner";
     
    export class News extends Component {
     
      static defaultProps = {
        pageSize: 6,
        totalResults: 30,
        category: "general",
      };
     
      state = {
        articles: [
          {
            title: "React 19 Released",
            description: "React 19 brings exciting improvements for developers.",
            urlToImage: "",
            url: "#",
          },
          {
            title: "GitHub Pages Hosting Made Easy",
            description: "Deploy your React app for free using GitHub Pages.",
            urlToImage: "",
            url: "#",
          },
          {
            title: "JavaScript ES2025 Features",
            description: "Explore the newest JavaScript features landing in 2025.",
            urlToImage: "",
            url: "#",
          },
        ],
        page: 1,
        loading: false,
        pageSize: this.props.pageSize,
      };
     
      fetchArticles = () => {
        this.props.topLoadingBarRef.current.continuousStart();
        this.setState({ loading: true });
     
        setTimeout(() => {
          this.setState({ loading: false });
          this.props.topLoadingBarRef.current.complete();
        }, 1000);
      };
     
      componentDidMount() {
        this.fetchArticles();
      }
     
      handlePrevClick = () => {
        this.setState({ page: this.state.page - 1 }, () => {
          this.fetchArticles();
        });
      };
     
      handleNextClick = () => {
        this.setState({ page: this.state.page + 1 }, () => {
          this.fetchArticles();
        });
      };
     
      handlePageSizeChange = (e) => {
        const newSize = Number(e.target.value);
        this.setState({ pageSize: newSize, page: 1 }, () => {
          this.fetchArticles();
        });
      };
     
      render() {
        const { totalResults, category } = this.props;
        const { page, pageSize, articles, loading } = this.state;
     
        return (
          <div className="container my-4">
            <h2 className="text-center mb-4 text-capitalize">
              Top {category} Headlines 📰
            </h2>
     
            <div className="d-flex justify-content-end mb-3">
              <label className="me-2 align-self-center fw-bold">Articles per page:</label>
              <select
                className="form-select w-auto"
                value={pageSize}
                onChange={this.handlePageSizeChange}
              >
                <option value="3">3</option>
                <option value="6">6</option>
                <option value="9">9</option>
                <option value="12">12</option>
              </select>
            </div>
     
            {loading ? (
              <Spinner />
            ) : (
              articles.map((article, index) => (
                <NewsItem
                  key={index}
                  title={article.title}
                  description={article.description}
                  imageUrl={article.urlToImage}
                  newsUrl={article.url}
                />
              ))
            )}
     
            <div className="d-flex justify-content-between my-4">
              <button
                className="btn btn-warning"
                onClick={this.handlePrevClick}
                disabled={loading || page <= 1}
              >
                &larr; Previous
              </button>
     
              <span className="align-self-center fw-bold">
                Page {page} of {Math.ceil(totalResults / pageSize)}
              </span>
     
              <button
                className="btn btn-warning"
                onClick={this.handleNextClick}
                disabled={loading || page >= Math.ceil(totalResults / pageSize)}
              >
                Next &rarr;
              </button>
            </div>
     
          </div>
        );
      }
    }
     
    export default News;
    ---

    How Routing & the Loading Bar Work Together

    Piece Role Triggered By
    BrowserRouter Enables client-side routing for the whole app Wraps <App /> in index.js
    Routes / Route Maps each category URL to a News component instance User navigates via the Navbar links
    NavLink Renders navigation links and highlights the active category Clicked by the user in the Navbar
    topLoadingBarRef Lets a child (News) control the parent's LoadingBar imperatively continuousStart() and complete() calls inside fetchArticles
    ---

    Features and Learnings:-

  • Understood what React Router DOM is and why it's essential for multi-page SPAs.
  • Installed and configured react-router-dom and react-top-loading-bar.
  • Wrapped the app with BrowserRouter in index.js.
  • Built a Navbar component with NavLink for category navigation.
  • Created dedicated routes for Business, Entertainment, General, Health, Science, Sports, and Technology.
  • Used a ref to control a top loading bar from a child component.
  • Triggered the loading bar during pagination, page size changes, and category switches.
  • Prepared the app for the next step: fetching real articles from a News API per category.
  • 📢 Important Note 📢

    How did you feel about this post?

    😍 🙂 😐 😕 😡

    Was this helpful?

    👍 👎