简体   繁体   中英

React show loading spinner while DOM is rendering

I have a list with items that first loads 30 items and if the user clicks on "Load All", rest of the items are shown:

+---------------------------------------------------------+
|                                                         |
|                           List                          |
|                                                         |
|                                                         |
|                                                         |
+---------------------------------------------------------+
|                       Load All Button                   |
+---------------------------------------------------------+

When the list is big (more than 1K items) the rendering of the "Load All" step takes some time and meanwhile the DOM is stuck and not responsive.

What is the right way to tap into React's lifecycle events so that upon clicking the button it will change to a loading spinner and when the list is fully rendered and ready it will change back ?

I have tried separating the two parts (list and button) to two components and wrap them in a parent component that holds a "loading" and then changing the state in the List componentDidUpdate function, but it didn't work

jsfiddle

http://jsfiddle.net/wh4z60m6/4/

Rendering in React is synchronous, which means nothing else can run alongside it.

You could render your list progressively since the user's screen probably can't display more than a hundred items at a time.

Also, note that rendering thousands of items is much slower in the development build than in the production build of React.

EDIT: Another option would be to first render the loader, then render your list items on the next frame. The loader will be displayed until the list items have finished rendering.

React.createClass({
    getInitialState: function() {
        return {
            loading: false,
            showAll: false,
        };
    },

    _showAll: function() {
        this.setState({ showAll: true, loading: true }, function() {
            // Using setTimeout here ensures that the component will wait until
            // the next frame before trying to render again.
            this.setTimeout(function() {
                this.setState({ loading: false });
            }.bind(this), 1000 / 60);
        });
    },

    render: function() {
        var amount = (this.state.showAll && !this.state.loading) ? 100000 : 3;
        return (
            <div>
                <button onClick={this._showAll}>
                    {this.state.loading ? 'Loading...' : 'Show all'}
                </button>
                {items.slice(0, amount).map(renderItem)}
            </div>
        );
    },
});

Here is a simple class with a more recent, React 16 example (with comments inline for clarity):

class People extends Component {
   state = {
      rows: [],
      loaded: false
   }
   /* lifecycle hook - keeping mind we are manipulating the DOM */
   /* within the component so we need to know the component/dom is ready */
   componentDidMount(){
      let self = this;
      /* returns a fetch() call stored in context passed down */
      /* through a higher order component */
      this.props.context.getPeople() 
        .then(json => { self.setState({rows:json.rows, loaded: true}); })
        /* Notice that loaded is set to true in the state object */
   }

   loading = () => (
      <div className={this.state.loaded?'ajax-loaded':'ajax-loading'}>LOADING</div>
      /* The class ajax-loaded -- you guessed it, hides the div */
      /* The thing to always keep in mind -- when state changes, things happen! */
   );
   render() {
       return (
           <div>
               {this.loading()}
               {this.state.rows.map(row => ( <div>{row.first} {row.last}</div>) )}
               {/* Again, when state changes, things happen! */}
           </div>
       )
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM