Display spinner during AJAX call when using fetch API Display spinner during AJAX call when using fetch API ajax ajax

Display spinner during AJAX call when using fetch API


There you go, I think the code is pretty much self-explanatory:

// Store a copy of the fetch functionvar _oldFetch = fetch; // Create our new version of the fetch functionwindow.fetch = function(){    // Create hooks    var fetchStart = new Event( 'fetchStart', { 'view': document, 'bubbles': true, 'cancelable': false } );    var fetchEnd = new Event( 'fetchEnd', { 'view': document, 'bubbles': true, 'cancelable': false } );    // Pass the supplied arguments to the real fetch function    var fetchCall = _oldFetch.apply(this, arguments);    // Trigger the fetchStart event    document.dispatchEvent(fetchStart);    fetchCall.then(function(){        // Trigger the fetchEnd event        document.dispatchEvent(fetchEnd);    }).catch(function(){        // Trigger the fetchEnd event        document.dispatchEvent(fetchEnd);    });    return fetchCall;};document.addEventListener('fetchStart', function() {    console.log("Show spinner");});document.addEventListener('fetchEnd', function() {    console.log("Hide spinner");});

Here's a live example: https://jsfiddle.net/4fxfcp7g/4/


Fetch in thenable, you can add spinner stop function in then(), that is called after response is received. And wrap it in another function for headers and hooking.

function ajax(someUrl, method) {    var myHeaders = new Headers();    var myInit = {         method: method,        headers: myHeaders    };    showSpinner();    return fetch(someUrl, myInit).then(function(response) {        //... do some with response        hideSpinner();        return response;    }).catch(function(error) {        //... tell the user the request failed and hide the spinner        hideSpinner();        return error;    });}ajax('example.com').then(function(response) {    // ...}).catch(function(error) {    // show error});


The main issue I have found using the setting manually a "loading" flag to true / false is that is quite easy to skip by mistake the set to false flag and your application would like hanged), and on the other hand I dont' want to mess up when several ajax request are being called in parallel, this comes even more harder when you want to track some of them, but in other cases you want to make silent requests.

I have created a microlibrary called react-promise-tracker to handle this in a more automatic way. How it works

Install promise tracker

npm install react-promise-tracker --save

Implement a simple loading indicator component (you can add the style you need for it), and wrap it with the promiseTrackerHoc

import { promiseTrackerHoc } from 'react-promise-tracker';const InnerLoadingIndicator = props => (   props.trackedPromiseInProgress &&   <h1>Hey some async call in progress ! Add your styling here</h1>);export const LoadingIndicator = promiseTrackerHoc(InnerLoadingIndicator);

Instantiate it in your application root component:

render(  <div>    <App />    <LoadingIndicator/>  </div>,  document.getElementById("root"));

Whenever you want to track a fetch or any promise based call (including async/await), just wrap it with the react-promise-tracker function trackPromise:

import { trackPromise } from 'react-promise-tracker';export class MyComponent extends Component {  componentWillMount() {    trackPromise(      userAPI.fetchUsers()        .then((users) => {          this.setState({            users,          })        })    );  }  // ...}

More resources:- Step by step tutorial (including adding a nice looking spinner): https://www.basefactor.com/react-how-to-display-a-loading-indicator-on-fetch-calls