[英]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號請求數據。
asyncCall
, asyncCall
會以錯誤的順序返回結果-您單擊一次返回並請求第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.