![](/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.