当我的React组件通过AJAX获取时显示加载微调器/ gif的最佳方法?

时间:2017-02-21 05:53:06

标签: javascript ajax reactjs

想象一下,我有一个非常简单的React组件,它显示了this.state.myList中存储的元素列表(参见下面的示例)

点击底部的“刷新”按钮会使React查询后端服务器并检索随后将显示的更新列表。该列表的实际内容或实现是无关紧要的。

var Foo = React.createClass({
  handleButtonClick: function() {
    return $.ajax({
      type: "POST",
      url: "/some/refresh/url",
      data: JSON.stringify({}),
      dataType: "json",
      contentType: "application/json",
      success: (function(response){
        self.setState({ myList: response.list });
      })
    });
  },

  render: function() {
    return (
      <div className="container">
        <ul>
          {
            this.state.myList.map(function(item) {
              return <li id="{item.id}">{item.name}</li>
            });
          }
        </ul>

        <input type="submit" value="REFRESH LIST" onClick={this.handleButtonClick} />
      </div>
    );
  }
});

假设AJAX调用(无论出于何种原因)需要几秒钟。在此期间,我希望展示一个标准的“加载”或“旋转器”gif,让用户知道它正在工作。

这样做的最佳方法是什么?

  • 在AJAX调用之前,我可以手动更新DOM并插入一个微调器gif,但这似乎不是“React方式”。而且我不知道对反应维持的ReactDOM会产生什么影响。

  • 我可以跟踪isLoading的状态,并在加载时显示微调器而不是列表。但后来我需要render()某事,然后立即启动另一个AJAX动作调用。

任何帮助表示感谢。

谢谢!

3 个答案:

答案 0 :(得分:9)

我总能解决这个问题的方法是让组件在其状态下跟踪fetchInProgress

在进行提取之前,请将此值设置为true;当提取完成(成功或失败)时,您将值设置回false

组件的render方法然后尊重这个标志;如果标志为true,则呈现微调器而不是数据集。

var Foo = React.createClass({
    handleButtonClick: function() {

        // before making call, set fetch flag
        self.setState({ fetchInProgress: true });

        return $.ajax({
            type: "POST",
            url: "/some/refresh/url",
            data: JSON.stringify({}),
            dataType: "json",
            contentType: "application/json",
            success: (function(response) {
                // when updating with dataset, also reset fetch flag
                self.setState({
                    fetchInProgress: false,
                    myList: response.list
                });
            }),
            failure: ((function(reason) {
                // make sure to reset even if fetch fails!
                self.setState({
                    fetchInProgress: false
                });
            })
        });
    },

    render: function() {
        return (
            <div className="container">
                <ul>
                    {
                        this.state.fetchInProgress
                            : <Spinner />
                            : this.state.myList.map(function(item) {
                                    return <li id="{item.id}">{item.name}</li>
                                })
                    }
                </ul>

                <input type="submit" value="REFRESH LIST" onClick={this.handleButtonClick} />
            </div>
        );
    }
});

答案 1 :(得分:4)

React模型是以UI作为您所在州的代表而构建的。这意味着您应该将状态建模为“必要数据是什么”,isLoading的返回值就是您显示数据的方式。

在您的情况下,您应该跟踪render()并在var Foo = React.createClass({ getInitialState: function() { return {isLoading: false}; }, handleButtonClick: function() { this.setState({ isLoading: true }); return $.ajax({ type: "POST", url: "/some/refresh/url", data: JSON.stringify({}), dataType: "json", contentType: "application/json", success: (function(response){ self.setState({ myList: response.list, isLoading: false }); }) }); }, render: function() { return ( <div className="container"> <ul> { this.state.myList.map(function(item) { return <li id="{item.id}">{item.name}</li> }); } </ul> {this.state.isLoading && <Spinner />} <input type="submit" value="REFRESH LIST" onClick={this.handleButtonClick} /> </div> ); } }); 中根据您所在州的值有条件地显示微调器。

depends_on:
  kafka:
    condition: service_healthy

答案 2 :(得分:2)

来自@ Tom的答案的小编辑。

render: function() {
    return (
        <div className="container">
            <ul>
                {
                    this.state.fetchInProgress ?
                        <Spinner />
                    :
                        this.state.myList.map(function(item) {
                            return <li id="{item.id}">{item.name}</li>
                        })
                }
            </ul>

            <input type="submit" value="REFRESH LIST" onClick={this.handleButtonClick} />
        </div>
    );
}