![](/img/trans.png)
[英]this.setState making infinite loop outside of array.map function
[英]setState is only executing once in Array.map function
我有一個用於遍歷新上傳文件的Array.map函數。
由於用戶可以多次上傳文件,因此必須將文件一起添加到一個陣列中。
因此,我正在使用以下代碼
onFileSelect = e => {
//FileList to array
const files = [...e.target.files];
files.map(file => {
this.setState({ invoices: [...this.state.invoices, file]})
});
}
問題在於setState僅在最后一項上執行。 因此,如果nuser選擇5個文件,則只有最后一個進入狀態。
一種可能的解決方案是獲取擴展數組,推送新文件並在map函數之外執行一個setState,但是我想知道為什么或如何將多個setStates集成到一個map函數中。
這工作
onFileSelect = e => {
//FileList to array
const files = [...e.target.files];
const invoiceArr = this.state.invoices;
files.map(file => {
invoiceArr.push(file)
});
this.setState({invoices: invoiceArr});
}
那是因為React會批處理狀態,這意味着setState
實際上並沒有設置狀態,而是將狀態轉換添加到隊列中,然后在某個時間執行。 因此,在您的情況下,隊列將如下所示(偽代碼):
original -> original + files[0]
original -> original + files[1]
original -> original + files[2]
// flattened to:
original -> original + files[2]
如您所見,狀態互不依賴。 因此,react只會采用最后一個狀態,並且您只會看到最后一個文件。 相反,您可以使一個狀態依賴於前一個狀態:
files.forEach(file => {
this.setState(previous => ({
invoices: [...previous.invoices, file]
}));
});
這導致隊列看起來像:
original -> original + files[0]
previous -> previous + files[1]
previous -> previous + files[2]
// flattened to
original -> original + files[0] + files[1] + files[2]
但是實際上您可以一步添加所有文件:
this.setState(previous => ({ invoices: previous.invoices.concat(files) }));
TLDR:如果狀態取決於先前的狀態,請不要設置狀態。
setState
內的this.state
被禁止,並且只能“偶然”工作。
第一個循環的問題是每次迭代都覆蓋現有項目,並且由於setState是異步的,因此這樣做是不安全的
為什么不這樣做呢?
onFileSelect = e => {
//FileList to array
const files = [...e.target.files];
this.setState({ invoices: []})
files.each(file => this.state.invoices.push(file)});
}
第二個選項似乎是正確的。
如果要返回新數組,應使用map函數。
您還可以使用reduce
:
onFileSelect = e => {
const files = [...e.target.files];
const invoiceArr = this.state.invoices;
let invoicesUpdated = files.reduce((acc, file) => {
acc.push(file);
return acc;
}, invoiceArr);
this.setState({invoices: invoicesUpdated});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.