簡體   English   中英

反應-異步調用具有意外的返回順序

[英]React - Async calls with an unexpected return order

我有一個react組件(我們稱它為Logs ),其中包括另一個react組件(我們稱它為DateChanger ),就本例而言,它僅用於更改父組件的日期。 當Logs獲得日期更改時,它將進行一次異步調用,以使用服務器中的數據更新其自身的狀態:

class Logs extends React.Component {
    ....

    onDateChange(newDate) {
        this.setState({loading: true, date: newDate});
        asyncCall(newDate)
            .then(results => {
                this.setState({data: results, loading: false})
            });
    }

    render() {
        return (
            ....
            <DateChanger onChange={this.onDateChange}>
            ....
        )
    }
}

我遇到的問題是,如果有人快速連續兩次更改日期,則呈現的“數據”並不總是來自正確的日期。

因此,我的具體意思是,在此示例中,DateChanger具有一個按鈕,可以將日期向前和向后更改1天。 因此,今天是5號,有人可以單擊日期更改器上的后退按鈕以從4號請求數據,然后再次單擊它以從3號請求數據。

asyncCallasyncCall會以錯誤的順序返回結果-您單擊一次返回並請求第4個,然后再次單擊它並請求第3個,然后返回第4個,有時服務器會返回第3個的數據,並且然后第4的數據,因為這是最近它呈現給用戶第四屆數據.then進行處理。

無論哪個服務器調用首先返回,React如何確保從第三位而不是第四位呈現數據?

[edit]這與使用setState回調無關。 如果將asyncCall移到setState回調中,則此問題仍然存在。 (盡管如果您想建議我將asyncCall移到setState回調中,我會很樂意接受該建議-但這並不能解決我的問題)

對於一種快速而骯臟的解決方案,您可以檢查得到的響應是否是您的組件正在尋找的響應。

onDateChange(newDate) {
    this.setState({loading: true, date: newDate});
    asyncCall(newDate)
        .then(results => {
            // Update state only if we are still on the date this request is for.
            if (this.state.date === newDate) {
                this.setState({data: results, loading: false})
            }
        });
}

但是,這樣的解決方案具有更好的關注點分離和更高的可重用性。

// Request manager constructor.
// Enables you to have many different contexts for concurrent requests.
const createRequestManager = () => {
    let currentRequest;

    // Request manager.
    // Makes sure only last created concurrent request succeeds.
    return promise => {
        if (currentRequest) {
            currentRequest.abort();
        }

        let aborted = false;

        const customPromise = promise.then(result => {
            if (aborted) {
                throw new Error('Promise aborted.');
            }

            currentRequest = null;

            return result;
        });

        customPromise.abort = () => {
            aborted = true;
        };

        return customPromise;
    };
};

class Logs extends React.Component {
    constructor(props) {
        super(props);

        // Create request manager and name it “attemptRequest”.
        this.attemptRequest = createRequestManager();
    }

    onDateChange(newDate) {
        this.setState({loading: true, date: newDate});
        // Wrap our promise using request manager.
        this.attemptRequest(asyncCall(newDate))
            .then(results => {
                this.setState({data: results, loading: false})
            });
    }

    render() {
        return (
            ....
            <DateChanger onChange={this.onDateChange}>
            ....
        )
    }
}

請記住,我們實際上並沒有中止請求,只是忽略了它的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM