Adding spinners and notifications to your React app
Tags: react, javascript
Published: 2019-09-04 19:57:33

---
title: Adding spinners and notifications to your React app
published: true
tags: react, javascript
canonical_url: https://blog.logrocket.com/spinners-notifications-react-app/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/gpucs3ttl846nk3r50pc.jpeg
---
**Written by [Nur Islam](https://blog.logrocket.com/author/nurislam/)**✏️

To make your web projects more interactive and user-friendly, you may find you want to add some additional features like notifications, or a spinner that shows a loading state.

Today we are going to explore how we can implement those features. Rather than simply showing some examples, we will focus on how we can integrate them into a full-stack project.

## Before we start…

So what exactly are we going to discuss here?

1. We will review all the necessary steps needed to add a spinner (to indicate loading, for example) to our project.
2. We will manage notifications using only one ‘Notification Container’ in our project and learn how we can use them to display with proper message. We are going to discuss two different npm packages for this so that we can compare them a bit.

Here I’ll use an existing MERN project to which we can add those features to see the outcome. I’m not going to discuss this existing project in depth since our aim here is just to show the implementation and integration of the above features.

In fact, we already have a good tutorial for that project in two parts, which explain everything you’ll need to understand. If you want, you can give the [first part a read here](https://dev.to/bnevilleoneill/mern-stack-a-to-z-part-1-564j). The [second part is available here](https://dev.to/bnevilleoneill/mern-stack-a-to-z-part-2-26pi).

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

### Resources

[Here](https://github.com/nurislam03/MERN_A_to_Z) is the GitHub repo for the server side of the project, and [here is the repo](https://github.com/nurislam03/MERN_A_to_Z_Client) for the client side. Just clone or download them, whatever you prefer, and run them either by following the instructions provided in the `README.md` file or those provided below.

To start running the server, make sure you are in the `MERN_A_to_Z/` directory and type the following commands:

```jsx
$ npm install
$ npm run app
```

> NOTE: We just need the running server. After that, we don’t have to make any changes there.

To start the client server, make sure you are in the `MERN_A_to_Z_Client/mern_a_to_z_client/` directory and type the following commands:

```jsx
$ npm install
$ npm start
```

> NOTE: We’ll work strictly in our client project; all changes will occur there.

Now that you have both the server and client sides of the project running, visit [http://localhost://3000](http://localhost://3000) to see the project live.

## Spinner setting

Here I’m going to add a loading spinner to our existing MERN project. We will update our `ShowBookList.js` file to add a loading spinner in the `ShowBookList` component.

So, create a folder named `common` inside the component folder. The path should like this: `MERN_A_to_Z_Client/mern_a_to_z_client/src/components/common`. Now, inside the `common` folder, create a file named `Spinner.js` and add a .gif file for a loading spinner.

You can find different kinds of .gif files free all over the internet, or you can use the one provided with the source code.

Now, update your `Spinner.js` with the following code:

```jsx
import React from 'react';
import spinner from './spinner.gif';

export default () => {
  return (
    <div>
      <img
        src={spinner}
        style={{ width: '340px', margin: 'auto', display: 'block' }}
        alt="Loading..."
      />
    </div>
  );
};
```

> NOTE: Here we import the .gif file (`import spinner from './spinner.gif';`). If you’re using your own, different spinner file, replace `spinner.gif` with the filename you want to add.

Now, update your `ShowBookList.js` file with this:

```jsx
import React, { Component } from 'react';
import '../App.css';
import axios from 'axios';
import { Link } from 'react-router-dom';
import BookCard from './BookCard';

// spinner file
import Spinner from './common/Spinner';

class ShowBookList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: true,
      books: []
    };
  }
```

Here we import our `Spinner` component from `common/Spinner.js` and use some logic inside the render function for assigning a value to `bookList`. We also added a loading state initially set to `false` inside the constructor.

You don’t need to follow the same logic; you can write in your own way, and obviously, it will be different depending on your project type.

Now, run the project and visit: [http://localhost:3000/](http://localhost:3000/)

You will see a Loading spinner like the following one for a very short period of time. This is the delay time of fetching data through the API. That means this spinner will be shown until the state value of `books` (`this.state.books`) is `null` or `loading` (`this.state.loading`) is `true`.

![Books List With Loading Spinner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/books-list-spinner-notification.png?resize=730%2C612&ssl=1)

You can adjust the background color of the spinner, or you can, of course, use a customized spinner. Here my goal was just to show where and when we can use spinners and how can we set up a spinner.

## Configuring notifications with react-notifications

Now I’ll show how we can handle notifications in our React project. First we’ll be using [react-notifications](https://www.npmjs.com/package/react-notifications), which, as its name suggests, is a notification component for React.

### Package installation

Go to the client project directory (`MERN_A_to_Z_Client/mern_a_to_z_client/`) and install the following npm package:

```jsx
$ npm install --save react-notifications
```

Run the project again.

### Setting up the notification container

Now update the `App.js` file. Import `NotificationContainer` from react-notifications and the `notifications.css` file.

```jsx
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import './App.css';

import CreateBook from './components/CreateBook';
import ShowBookList from './components/ShowBookList';
import ShowBookDetails from './components/ShowBookDetails';
import UpdateBookInfo from './components/UpdateBookInfo';

// React Notification
import 'react-notifications/lib/notifications.css';
import { NotificationContainer } from 'react-notifications';

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          <Route exact path='/' component={ShowBookList} />
          <Route path='/create-book' component={CreateBook} />
          <Route path='/edit-book/:id' component={UpdateBookInfo} />
          <Route path='/show-book/:id' component={ShowBookDetails} />
          <NotificationContainer />
        </div>
      </Router>
    );
  }
}

export default App;
```

So far, so good — we have completed our setup for `NotificationContainer`.

> NOTE: Use only one `NotificationContainer` component in the app.

Now it’s time to pass notifications from different components to display their message.

### Setting notifications from components

Here you just have to import the `NotificationManager` from react-notifications. After that, you are ready to pass notifications through `NotificationManager`.

Look at the changes I have made in the `CreateBook.js` file to pass notifications from the `CreateBook` component.

Open `CreateBook.js` and update it with the following code:

```jsx
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import '../App.css';
import axios from 'axios';

// React Notification
import { NotificationManager } from 'react-notifications';

class CreateBook extends Component {
  constructor() {
    super();
    this.state = {
      title: '',
      isbn:'',
      author:'',
      description:'',
      published_date:'',
      publisher:''
    };
  }

  onChange = e => {
    this.setState({ [e.target.name]: e.target.value });
  };

  onSubmit = e => {
    e.preventDefault();

    const data = {
      title: this.state.title,
      isbn: this.state.isbn,
      author: this.state.author,
      description: this.state.description,
      published_date: this.state.published_date,
      publisher: this.state.publisher
    };

    axios
      .post('http://localhost:8082/api/books', data)
      .then(res => {
        this.setState({
          title: '',
          isbn:'',
          author:'',
          description:'',
          published_date:'',
          publisher:''
        })
        this.props.history.push('/');
        NotificationManager.success('You have added a new book!', 'Successful!', 2000);
      })
      .catch(err => {
        // console.log("Error in CreateBook!");
        NotificationManager.error('Error while Creating new book!', 'Error!');
      })
  };

  render() {
    return (
      <div className="CreateBook">
        <div className="container">
          <div className="row">
            <div className="col-md-8 m-auto">
              <br />
              <Link to="/" className="btn btn-outline-warning float-left">
                  Show BooK List
              </Link>
            </div>
            <div className="col-md-8 m-auto">
              <h1 className="display-4 text-center">Add Book</h1>
              <p className="lead text-center">
                  Create new book
              </p>

              <form noValidate onSubmit={this.onSubmit}>
                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='Title of the Book'
                    name='title'
                    className='form-control'
                    value={this.state.title}
                    onChange={this.onChange}
                  />
                </div>
                <br />

                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='ISBN'
                    name='isbn'
                    className='form-control'
                    value={this.state.isbn}
                    onChange={this.onChange}
                  />
                </div>

                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='Author'
                    name='author'
                    className='form-control'
                    value={this.state.author}
                    onChange={this.onChange}
                  />
                </div>

                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='Describe this book'
                    name='description'
                    className='form-control'
                    value={this.state.description}
                    onChange={this.onChange}
                  />
                </div>

                <div className='form-group'>
                  <input
                    type='date'
                    placeholder='published_date'
                    name='published_date'
                    className='form-control'
                    value={this.state.published_date}
                    onChange={this.onChange}
                  />
                </div>
                <div className='form-group'>
                  <input
                    type='text'
                    placeholder='Publisher of this Book'
                    name='publisher'
                    className='form-control'
                    value={this.state.publisher}
                    onChange={this.onChange}
                  />
                </div>

                <input
                    type="submit"
                    className="btn btn-outline-warning btn-block mt-4"
                />
              </form>
          </div>
          </div>
        </div>
      </div>
    );
  }
}

export default CreateBook;
```

Run the project and visit [http://localhost:3000/create-book](http://localhost:3000/create-book). Now you will see a message like the following after creating a new book. You will also get an error message if the system fails to add a new book.

![Books List Success Notification](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/books-list-notification.png?resize=730%2C639&ssl=1)

You can apply this same method in different components in your project. Notifications will be displayed in different colors depending on the notification type: info, success, warning, and error.

You can also pass five different parameters along with the message: `message`, `title`, `timeOut`, `callback`, and `priority`.

### Available `NotificationManager` APIs

For this package, there are four different APIs available to us of the following types:

- `info`
- `success`
- `warning`
- `error`

Here’s an example for the `success` type — simply replace `success` with the proper notification type for the given scenario:

```jsx
NotificationManager.success(message, title, timeOut, callback, priority);
```

The parameters that follow the notification type are described below:

- `message`: the message we want to pass. It has to be a string.
- `title`: The title of the notification. Again, its type is string.
- `timeOut`: The popup timeout in milliseconds. This has to be an interger.
- `callback`: We can pass a function (type; function) through the notification. It executes after the popup is called.
- `priority`: This is a boolean parameter. We can push any notification to the top at any point by setting the priority to true.

## Configuring notifications with react-toastify

Now that we have discussed react-notifications, let’s move on to [react-toastify](https://www.npmjs.com/package/react-toastify). Both packages serve a similar purpose, but react-toastify has more built-in features than react-notifications, and it is also more open to customization.

Now on version 5.3.2, it is clear the react-toastify team has a good eye on maintenance. Additionally, react-toastify is almost 16 times more popular than react-notifications according to their weekly downloads record at the time of writing.

react-toastify was built with many features, some of which are:

- Easy to integrate
- Customizable
- Allows users to close displayed notifications by swiping
- A fancy progress bar to display the remaining time on the notification

For this part, I want to create a new project to show the whole setup. Let’s use create-react-app to get an initial setup for our React project.

```jsx
$ npx create-react-app react-notification-example
```

From the project directory (`react-notification-example`), run the project:

`$ npm start`

Now, open the `App.js` file and update it with this:

```jsx
import React from 'react';
import './App.css';


class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      total_file_size: 0,
      download_limit: 100
    };
  }

  add_to_download_card = size => {
    if(this.state.total_file_size + size <= this.state.download_limit) {
      this.setState({
        total_file_size: this.state.total_file_size + size
      });
    }
  };

  reset = e => {
    this.setState({
      total_file_size: 0
    });
  }


  render() {
    return (
      <div className="App">
          <header className="App-header">
            <div>
              <button className='inc' onClick={() => this.add_to_download_card(40)}>
                Download A(40GB)
              </button>

              <button className='inc' onClick={() => this.add_to_download_card(80)}>
                Download B(80GB)
              </button>

              <button className='inc' onClick={() => this.add_to_download_card(30)}>
                Download C(30GB)
              </button>
            </div>

            <div>
              <button className='reset' onClick={this.reset}>
                Reset
              </button>
            </div>

            <b>
              Download Limit: {this.state.download_limit} GB
            </b>

            <h1>
              Total File Size: {this.state.total_file_size} GB
            </h1>
          </header>
      </div>
    );
  }
};

export default App;
```

This update will change the view of your [http://localhost:3000/](http://localhost:3000/), and you should see the following page on your browser:

![Our App In A Web Browser](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/web-app-browser.png?resize=730%2C614&ssl=1)

Here you have three options to download three different files by clicking them. Once you click any of them, **Total File Size** will display the updated number (total number of GB you have downloaded). We set the download limit to 100. You can change them, of course, and there is also a **Reset** button to reset the total download size.

> NOTE: This app doesn’t have any server functionality, and those **Download** buttons won’t download any file. It’s just a counter that counts total downloaded file size. This is enough to show the uses of react-toastify.

### react-toastify installation

From your project folder (`react-notification-example`), run the command for your preferred package manager to install react-toastify:

```jsx
$ npm install --save react-toastify
$ yarn add react-toastify
```

Now, update `App.js` with these two lines to import the necessary stuff for react-toastify:

```jsx
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
```

After that, add `ToastContainer` inside the render function _once_ in your application tree. If you are not sure where to put it, then rendering it in the application root would be the best option.

```jsx
<ToastContainer position={toast.POSITION.TOP_RIGHT}/>
```

Position is optional here, but the default position value is the top right of your browser. If you want, you can replace the position value with any of the following:

- `TOP_LEFT`
- `TOP_CENTER`
- `TOP_RIGHT`
- `BOTTOM_LEFT`
- `BOTTOM_CENTER`
- `BOTTOM_RIGHT`

Now you can set notifications to pass through `ToastContainer`. I have added three different types of notifications — `success`, `error`, and `info` — inside the `add_to_download_card` and `reset` functions.

Our final `App.js` file should look like this:

```jsx
import React from 'react';
import './App.css';

// React-Toastify
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      total_file_size: 0,
      download_limit: 100
    };
  }

  add_to_download_card = size => {
    if(this.state.total_file_size + size <= this.state.download_limit) {
      this.setState({
        total_file_size: this.state.total_file_size + size
      });
      toast.success("You have downloaded a "+ size + " GB file Successfully!");
    } else {
      // notification
      toast.error("Download Limit Exceeded!");
    }
  };

  reset = e => {
    this.setState({
      total_file_size: 0
    });
    toast.info("Download Counter is initialized with 0");
  }


  render() {
    return (
      <div className="App">
          <header className="App-header">
            <div>
              <button className='inc' onClick={() => this.add_to_download_card(40)}>
                <b>Download A(40GB)</b>
              </button>

              <button className='inc' onClick={() => this.add_to_download_card(80)}>
                <b>Download B(80GB)</b>
              </button>

              <button className='inc' onClick={() => this.add_to_download_card(30)}>
                <b>Download C(30GB)</b>
              </button>
            </div>

            <div>
              <button className='reset' onClick={this.reset}>
                <b>Reset</b>
              </button>
            </div>

            <b>
              Download Limit: {this.state.download_limit} GB
            </b>

            <h1>
              Total File Size: {this.state.total_file_size} GB
            </h1>
          </header>
          <ToastContainer position={toast.POSITION.TOP_RIGHT}/>
      </div>
    );
  }
};

export default App;
```

You will get the following `success` notification after every successful downloading attempt:

![File Download Success Notification](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/success-notification.png?resize=730%2C617&ssl=1)

If you look at the notification closely, you’ll see there is a progress bar within the notification. This indicates the remaining display time for the notification.

You get the following `error` notification when you try to execute a download after exceeding or meeting the download limit:

![File Download Error Notification](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/error-notification.png?resize=730%2C616&ssl=1)

And it will show an `info` notification when you press the **Reset** button:

![File Download Info Notification](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/info-notification.png?resize=730%2C617&ssl=1)

You can also dismiss any notification by simply clicking it, or you can swipe them to the left or right.

react-toastify is fully customizable, and there are also many more exciting features to fulfill all your needs. You can check out the full documentation for react-toastify [here](https://github.com/fkhadra/react-toastify), and you can find the GitHub repo for the whole project [here](https://github.com/nurislam03/Notification_and_Spinner).

## Conclusion

Today we have discussed adding a spinner and two different packages for managing notifications in a React project. Both notification packages are popular and customizable.

react-notifications is simpler than react-toastity, but I would recommend react-toastify over react-notifications because the former is more popular and has more customizable options to go along with all the same features of react-notifications.
* * *
**Editor's note:** Seeing something wrong with this post? You can find the correct version [here](https://blog.logrocket.com/spinners-notifications-react-app/).

## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *
The post [Adding spinners and notifications to your React app](https://blog.logrocket.com/spinners-notifications-react-app/) appeared first on [LogRocket Blog](https://blog.logrocket.com).