componentWillReceiveProps和componentDidMount之间的竞争条件

时间:2015-11-02 16:42:38

标签: ajax reactjs

我有一个组件,它在props中获取一些数据,并向他们发出ajax请求。

var ItemList = React.createClass({
    propTypes: {
        filters: React.PropTypes.object.isRequired,
    },
    getInitialState: function() {
        return {items: []};
    },
    componentDidMount: function() {
        this.ajaxFetchItems(this.props.filters);
    },
    componentWillReceiveProps: function(nextProps) {
        this.ajaxFetchItems(nextProps.filters);
    },
    ajaxFetchItems: function(filter) {
        ....
        this.setState({items: data});
    }
}

问题是道具几乎立即被更改,有时componentDidMount中的ajax调用比componentWillReceiveProps中的ajax稍慢,所以初始状态是在第一次更新后写的。< / p>

如何避免缓慢的componentDidMount覆盖快速componentWillReceiveProps?

有更好的方法来处理下载数据的反应组件的生命周期吗?

1 个答案:

答案 0 :(得分:3)

您可以为处理的最新更新设置状态时间戳。 并以某种方式确保原始Ajax请求的时间戳包含在Ajax结果中。

添加shouldComponentUpdate()以检查收到的结果是否具有晚于状态时间戳的时间戳。如果不是:返回false,您的组件将忽略结果。

顺便说一句:根据定义,componentDidMountcomponentWillReceiveProps只能按此顺序运行。我怀疑你的第一个Ajax调用需要很长时间才能返回结果,而你的第二个调用很快。因此,您以错误的顺序返回Ajax结果。 (不是因为反应功能慢)。

更新: 使用shouldComponentUpdate是处理这种情况的反应方式:它的目的是允许比较新状态和旧状态,并基于该比较,而不是重新渲染。

问题(很可能)是由ajax响应进入的顺序生成的:

  1. Ajax调用1(在此示例中在componentDidMount中触发)
  2. Ajax调用2(在componentWillReceiveProps中触发,由组件的父元素触发)
  3. 来自电话2的回应载于
  4. 来自来电1的回复。
  5. 因此,更通用的问题/解决方案将用于&#34;如何处理以错误顺序返回的ajax响应&#34;。

    时间戳(在shouldComponentUpdate中)是一种方法。

    另一种选择(描述为here)是使第二个请求(在componentWillReceiveProps中)中止第一个ajax请求。

    <强>重温: 在进一步考虑之后(componentDidMount和componentWillReceiveProps中的调用感觉不对),一种更通用的反应方式来接近你的组件可能如下:

    您的组件的工作基本上是:

    • 通过prop接收过滤器,
    • 使用过滤器来获取带有ajax的列表,
    • 并渲染ajax reponse = list。

    所以它有2个输入:

    • filter(= prop)
    • list(= ajax response)

    且只有1个输出=列表(可能为空)。

    巷道:

    • 第一次组件接收过滤器作为prop:它需要发出ajax请求,并呈现一个空列表或一些加载状态。
    • 所有后续过滤器:组件应发出新的ajax请求(并杀死可能的未完成的旧请求),并且不应重新呈现(!)
    • 每当收到ajax响应时,它应该重新呈现列表(通过更新状态)。

    使用react设置它可能看起来像这样:

    getInitialState() {
      this.fetchAjax(this.props.filter);            // initiate first ajax call here
      return { list : [] };                         // used to maybe display "loading.." message
    }
    componentWillReceiveProps(nextProps) {
      this.fetchAjax(nextProps.filter);            // send off ajax call to get new list with new filter
    }
    shouldComponentUpdate(nextProps, nextState) {
      return (this.state.list != nextState.list);   // only update component if there is a new list
                                                    // so when new props (filter) comes in there is NO rerender
    }
    render() {
      createChildrenWith(this.state.list);
    }
    fetchAjax(filter) {
      killOutStandingRequests();                    // some procedure to kill old ajax requests
      getListAsync…
        request: filter                             // request new list with new filter
        responseHandler: this.handleResponse        // add responseHandler
    }
    responseHandler(data) {
      this.setState({ list : data });               // put the new list in state, triggering render
    }
    

    状态中的原始时间戳将解决上面发布的问题,但我认为我将共享修订后的反应组件作为奖励...