2015-11-02 139 views
2

我有一个组件,它在道具中获取一些数据并使用它们发出ajax请求。componentWillReceiveProps和componentDidMount之间的争用条件

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稍慢,因此初始状态的第一更新之后写入。

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

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

+0

如果下一个'filters'道具是从当前 – Lucius

+0

我尽量避免应用程序树中的应用程序逻辑的不同仅取它要重新加载,任何我的组件都会监​​听对商店的更改并且会更新完成加载后。如果你想,你只能更新商店,如果new_filters!== old_filters这意味着如果2 ajaxFetchItems快速连续启动它是一个无操作。 或者你可以在storeload – derekdreery

回答

3

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

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

顺便说一下:componentDidMountcomponentWillReceiveProps可以按照定义只能按该顺序运行。我怀疑你的第一个Ajax调用需要很长时间才能返回结果,而你的第二个调用很快。所以你会以错误的顺序返回Ajax结果。 (不是由于缓慢的反应功能)。

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

是在Ajax响应进来的顺序(最有可能)所产生的问题:

  1. Ajax调用1(在本例为componentDidMount解雇)
  2. Ajax调用2(在componentWillReceiveProps解雇,触发器由组分的亲本)来自呼叫2
  3. 响应进来
  4. 响应从呼叫1的用武之地。

因此,更通用的问题/解决方案将是“如何处理以错误顺序返回的Ajax响应”。

timestamp(在shouldComponentUpdate中)是执行此操作的一种方法。

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

再访: 给它一些进一步的思考(在componentDidMount和componentWillReceiveProps来电感觉不对),更普遍的反应般的方式实现你的分量大概会具体如下:

你组件的工作基本上是:

  • 接收通过道具过滤,
  • 使用过滤器来使用Ajax获取列表,
  • 并呈现ajax reponse =列表。

所以它有2个输入:

  • 滤波器(=丙)
  • 列表(= Ajax响应)

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

巷道:

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

    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 
    } 
    

    原来的时间戳,国家将解决上面贴的问题,但我想我会分享修订后的反应成分为:

与反应可能会是这个样子设置此功能所以在这种情况下,我过滤器应用到店,并告诉 - 奖金......

+0

是的,肯定是Ajax调用时间过长使用去抖,我不是很清楚。 你的解决方案可以工作,但没有更多的惯用方法?在我看来,一个如此常见的例子.. – fain182

+0

我觉得shouldComponentUpdate(时间戳)是反应-的方式来解决这个问题。其他通用解决方案也是可能的,例如使用承诺,或通过使第二个请求终止第一个请求。我在更新的答案中提供了通用JavaScript解决方案的链接。 – wintvelt

+0

我在答案中添加了一个通用清理反应组件。超出你的原始问题,但可能有帮助。 – wintvelt