简体   繁体   English

在DOM渲染时,React显示加载微调器

[英]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: 我有一个列表,其中包含首先加载30个项目的项目,如果用户点击“全部加载”,则会显示其余项目:

+---------------------------------------------------------+
|                                                         |
|                           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. 当列表很大(超过1K项)时,“全部加载”步骤的渲染需要一些时间,同时DOM被卡住而没有响应。

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 ? 什么是利用React的生命周期事件的正确方法,以便在单击按钮时它将更改为加载微调器,当列表完全呈现并准备就绪时它将更改回来?

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 我已经尝试将两个部分(列表和按钮)分成两个组件,并将它们包装在一个包含“loading”的父组件中,然后在List componentDidUpdate函数中更改状态,但它不起作用

jsfiddle 的jsfiddle

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

Rendering in React is synchronous, which means nothing else can run alongside it. React中的渲染是同步的,这意味着没有其他东西可以与它一起运行。

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. 另外,请注意,在开发构建中渲染数千个项目比在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): 这是一个简单的类,带有更新的React 16示例(为了清晰起见,注释内联):

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>
       )
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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