javascriptreactjsajaxloading-animation

What is the best way to create a Loading Animation for React JS Ajax calls?


I have a React JS (16.13.1) application - and I was interested in creating some loading animations to display in the container when that content is being loaded. I was hoping to do it in a way that could provide some reusability like the following example:

import React from "react";
...
import axios from "axios";
import LoadingAnimation from "[myloadinganimation]"

class Widget extends React.Component {
    constructor(props) {
        super(props);
        this.state = { widgets: [] };
    }

    getWidgets() {
        const data = new FormData();
        return axios.post('/my/api/url', data, window.globals.formPostHeaders)
               .then(res => {
                    const regions = res.data.regions.map(obj => obj);
                    this.setState({regions});
               });
        
    }


    render() {
         return (
              <>
                 <Table>
                     <tbody>
                     <tr>
                         <!-- desired component -->
                         <LoadingAnimation self={this} conds={{obj: this, cb: 'callback?'}} />
                         <!-- /desired component -->
                     </tr>
                     </tbody>
                 </Table>
              <>
         );

    }

}

In theory, what I would have is a component called LoadingAnimation that can be invoked on this page - preferably on page load, or even just whenever an AJAX request is kicked off. I realize that it would require some combination of listeners, callbacks and Promise's to do this. I just cannot figure out the right flow/order for this to appear.

For this to be reusable, I would have the component display the animation, do the listening for the completion of the ajax request, and then pass the data to the callback in the view component for rendering; so as to abstract the lifting away from the Animation component, but handling dispatching of the events or whatever they may be.

How can I accomplish this?


Solution

  • I am not sure if I get the reusable part. The most straight forward approach to handle loading is to take care of it in the state (as it is shown below). I don't know if it is resuable for you :

    class Widget extends React.Component {
      constructor(props) {
        super(props);
        this.state = { widgets: [], loading : false };
      }
    
      componentDidMount() {
        // to trigger on page load
        this.getWidgets()
      }
    
      async getWidgets() {
        this.setState({ loading: true})
        const data = new FormData();
        await axios.post('/my/api/url', data, window.globals.formPostHeaders)
          .then(res => {
            const regions = res.data.regions.map(obj => obj);
            this.setState({ regions });
          });
        this.setState({ loading : false})
      }
    
    
      render() {
        return (
                <>
                  <Table>
                    <tbody>
                      <tr>
                        { this.state.loading && <LoadingAnimation />}
                      </tr>
                    </tbody>
                  </Table>
                <>
              );
           }
    }
    
    

    If you wanna re-use this in different places, you better search for a way to spread the loading state around components and places you wanna re-use. You may use redux or flux libraries to handle state for such cases. There is also built-in Context API which might be useful too.