DEV Community

Lateef Adetona
Lateef Adetona

Posted on • Originally published at lateeflab.com

How to Display a Loading Spinner while DOM is rendering in ReactJS

Overview

Design is important step when creating any product. User experience is key when capturing and retaining the attention of users. Many users don't understand how large our applications truly are and how long things such as HTTP requests or build times could take. When they visit our website but they are introduced to a blank screen, they think the website could be broken and then travel to another website.

In this tutorial, we'll show you to polish your website's user experience by simply adding a big loading spinner when a user visits your site, to indicate that the other components of the website are still loading.

1. Setup your project

We have to setup our React project. In this tutorial, we're going to use create-react-app. In your terminal/CMD, type the following:

npx create-react-app loading-spinner

2. Edit index.html

First step to open index.html. We're going to add div with the "loader-container" class with a child div with the "loader" class. This will be the entry point for our loading spinner within our HTML. Remember, in ReactJS, your project is rendered within the index.html file, specifically within the root div. Adding our loading spinner class directly in the index.html means we can display the class when we start up our React app.

<!-- Loading Spinner Div -->
    <div class="loader-container">
      <div class="loader"></div>
   </div>
Enter fullscreen mode Exit fullscreen mode

Now that we've set the entry point within the HTML, lets write some CSS to design a loading spinner! In the same index.html, within the header tag, lets add some CSS.

<head>
    <!-- Loading Spinner Styling -->
    <style>
      .loader {
        border: 16px solid #f3f3f3;
        border-top: 16px solid #3498db;
        border-radius: 50%;
        width: 130px;
        height: 130px;
        animation: spin 2s linear infinite;
      }

      @keyframes spin {
        0%  { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
      </style>

</head>
Enter fullscreen mode Exit fullscreen mode

Here is how our full index.html should be at this point. Copy and paste the following in your index.html file:

<!-- .../public/index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>

    <!-- Loading Spinner Styling -->
    <style>
      .loader {
        border: 16px solid #f3f3f3;
        border-top: 16px solid #3498db;
        border-radius: 50%;
        width: 130px;
        height: 130px;
        animation: spin 2s linear infinite;
      }

      @keyframes spin {
        0%  { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
      </style>

  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>

    <!-- Loading Spinner Div -->
    <div class="loader-container">
      <div class="loader"></div>
   </div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

3. Edit App.js

Now, lets turn our attention to App.js. We're going to do 4 things:

Define a state variable so we can manage the state of our application
Define a function that simulates a request
Use the useEffect() React Hook to run our simulated request
Render our HTML, based on or state variable
First things first, we have to import useState and useEffect at the top of our App.js file.

//../src/App.js
import React, {useState, useEffect} from 'react';
Enter fullscreen mode Exit fullscreen mode

We can now define our state variable within App() function. Add the following directly after defining our App() function:

//../src/App.js

function App() {
  const [isLoading, setLoading] = useState(true);
Enter fullscreen mode Exit fullscreen mode

We utilize React Hooks useState() so we can keep track of the value (or state) of a variable throughout the lifecycle of our application. In this example, we're using useState() to keep track of a boolean type variable. We're going to switch the boolean from being "true" to "false" throughout our application. Moving on to our fake request, add the following directly under where we defined our state variable:

function someRequest() { //Simulates a request; makes a "promise" that'll run for 2.5 seconds
    return new Promise(resolve => setTimeout(() => resolve(), 2500));
  } 
Enter fullscreen mode Exit fullscreen mode

We defined a function, someRequest(), that returns a Promise(). A Promise() is a JavaScript method that takes in two arguments; a success callback and failure callback. We use a Promise() to simulate a resolve, knowingly it will fail, and our code will execute the failure callback, which is setting a timeout of 2.5 seconds (or 2500 milliseconds).

Now we can call the useEffect() React Hook to call our someRequest() function, which will remove our loader spinner div within the index.html and toggle our state variable. Copy and paste the following code after our someRequest() function:

useEffect(() => {
    someRequest().then(() => {
      const loaderElement = document.querySelector(".loader-container");
      if (loaderElement) {
        loaderElement.remove();
        setLoading(!isLoading);
      }
    });
  });
Enter fullscreen mode Exit fullscreen mode

Lastly, for our application to display the loading spinner on render, we have to add an except directly before our render() method. Add the following to your App.js right before the render() method:

if (isLoading) {
    return null;
  }
Enter fullscreen mode Exit fullscreen mode

And thats it go ahead and run your application with the following command in your terminal/CMD:

$ npm start
Now you have a loading spinner that displays as your application (presumedly making some sort of request to a server, as simulated with the use of our someRequest() function) and disappears when our application is finish rendering.

Check out the full article on LateefLab

Discussion (0)