2015-11-02 136 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