Comments

Create React loading spinner

Spinner improves user experience. Loading symbol gives users a feeling of “Content will appear soon”. This is definitely better than keeping users wondering about the current status. Lets create a react loading spinner!

For this react loading spinner tutorial, I’ll use a custom function that resolves after given seconds. I’ll also use the GitHub API to fetch my details. In both cases, the loading component will be visible until the data is fully loaded.

Setting Up

Use the starter project or use a terminal to create a new react app using create-react-app on Codesandbox.

Here is the Structure of the application:

  • App
    • Loader
    • ShowDetail

The loading screen is shown from loader initially. When the details are fetched, showDetail is rendered with all the details.

App Component

App initially renders Loader component, this will change in a while.

import React, { Component } from 'react';
import Loader from './Loader';

class App extends Component {
  render() {
    return <Loader />;
  }
}
export default App;

But let’s create the loader component.

Loader Component

Loader component will show a loading screen. For the loading icon, use font-awesome.

Insert this URL in the head section of /public/index.html.

<link rel="stylesheet" href=https://use.fontawesome.com/releases/v5.7.1/css/all.css>

If you’re using starter files, it’s already there.

In Loader.js, export Loader component.

import React from 'react';

function ShowDetail() {
  return (
    <div className="loader center">
      <i className="fa fa-cog fa-spin" />
    </div>
  );
}

export default ShowDetail;

The class center keeps it in the center of the screen vertically and horizontally while loader increases font size. All CSS is included in the index.css file.

Classes fa fa-cog refer to a font-awesome icon. Class fa-spin spins this icon. An alternative to fa-cog can be fa-spinner or fa-tools.

Now, you should see a spinning icon in the center of the browser.

ShowDetail Component

Once the details are fetched (in App component), they are passed to the ShowDetail component. It renders the details passed. Details are passed as props object. All details can be de-structured to use name instead of prop.details.name.

import React from 'react';

const ShowDetail = (props) => {
  const { name, company, blog, location, bio } = props.details;
  return (
    <div className="center">
      <div className="loaded">Details Loaded</div>
      <div>
        <strong>Name: </strong>
        {name}
      </div>
    </div>
  );
};

export default ShowDetail;

I’ve just rendered name, but there are other properties (company, blog, etc), duplicate the div and replace a name with those variables. This is a complete ShowDetail component.

import React from 'react';

const ShowDetail = (props) => {
  const { name, company, blog, location, bio } = props.details;
  return (
    <div className="center">
      <div className="loaded">Details Loaded</div>
      <div>
        <strong>Name: </strong>
        {name}
      </div>

      <div>
        <strong>Company: </strong>
        {company}
      </div>
      <div>
        <strong>Blog: </strong>
        {blog}
      </div>

      <div>
        <strong>Location: </strong>
        {location}
      </div>
      <div>
        <strong>Bio: </strong>
        {bio}
      </div>
    </div>
  );
};

export default ShowDetail;

App Component

We’ve created loader component and rendered it successfully. We’ve created ShowDetail Component but you haven’t rendered that.Let’s test the ShowDetail component before completing the App.

Change the App to render the ShowDetail.

import React, { Component } from 'react';
import Loader from './Loader';
import ShowDetail from './ShowDetail';

class App extends Component {
  render() {
    let name = 'Krissanawat';
    let details = { name };
    return <ShowDetail details={details} />;
  }
}

export default App;

The ShowDetail component needs details as props, so pass that as well.

Create a name variable, create details as an object with this  name as a key.

let details = { name };

Pass the details to ShowDetail

Expected behavior

Generally, loaders are used for fetching data from a source. Loading spinner shows until the request completes.

For this, declare a state loading as true initially.

state = {loading: true}

When the request is resolved, we’ll set loading to false.

Conditional rendering

In the render method in App, use conditional rendering

class App extends Component {
  state = { loading: true };
  render() {
    if (this.state.loading) return <Loader />;
    let name = 'Rabindra Joshi';
    let details = { name };
    return <ShowDetail details={details} />;
  }
}

If loading is true return loader, else it will continue to set name, details and renders ShowDetail.

But we don’t have a condition to change state so it’ll get stuck in Loader.

Use React Dev Tools to change this state to true and see the changes.

We’ll use state loading to keep track of the state of details.

Let the program Sleep

NodeJS is single threaded and waiting for x amount of time used to be an issue. I’ll use promise that resolves after 2 seconds.

Another method wait will await for the result from sleep before going through other tasks in the function.

sleep = (milliseconds) => {
    return new Promise((resolve) => setTimeout(resolve, milliseconds));
  };

Await can only be in an async function, so wait is an async function. Wait time is 2 seconds by default.

wait = async (milliseconds = 2000) => {
    await this.sleep(milliseconds);
    this.setState({
      login: 'Kris,
      name: 'Krissanawat',
      company: 'myself',
      blog: 'programmingwithmosh.com/author/krissanawat',
      location: 'Chaingmai, Thialadn',
      bio: 'JavaScript Developer',
      loading: false
    });
  };

Wait sets all the values of name, company, and others in a states. It also changes loading to false.

This needs to be reflected in the render method. Instead of declaring details in the render method, use the values from state.

render() {
    if (this.state.loading) return <Loader />;
    let { name, blog, company, location, bio } = this.state;
    let details = { name, blog, company, location, bio };

    return <ShowDetail details={details} />;
  }

Add a ComponentDidMount lifecycle to execute wait method. ComponentDidMount runs automatically when the component is rendered on the screen.

componentDidMount() {
    this.wait(2000);
  }

You can pass a wait time in milliseconds.

Now, a loading screen will appear for 2 seconds or 2000 milliseconds and then ShowDetails will render.

Demo

How to get the data from an API instead of manually declaring? The loader will show until the data is fetched. Let’s use the GitHub API to get my details.

fetchGitHub = () => {
    fetch('https://api.github.com/users/krissanawat')
      .then((res) => res.json())
      .then((res) => {
        let { login, name, company, blog, location, bio } = res;
        this.setState({
          login: login,
          name: name,
          company: company,
          blog: blog,
          location: location,
          bio: bio,
          loading: false
        });
      })
      .catch((error) => {
        console.log(error);
        this.wait();
      });
  };

It sets state from the response. If there’s an error, like the server is down or your internet connection is not working, it calls the wait method to set the states.

Don’t forget to set this method on ComponentDidMount.

componentDidMount() {
    this.fetchGitHub();
  }

It takes less than a second, you won’t see the loading screen for long.

Conclusion

Hopefully, this will help you to implement loading spinner in React. It also talks about Async Rendering and Conditional Rendering.

final output

Call to action

If you want to become a React master, check out Mosh’s React course. It’s the best React course out there!

 

Krissanawat is Nomad Web developer live in Chiangmai passionate on React and Laravel
Tags: ,

Leave a Reply

Connect with Me
  • Categories
  • Popular Posts