我有一个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,但是我想知道为什么或如何将多个setState集成到一个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});
}
答案 0 :(得分:5)
那是因为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:如果它取决于先前的状态,请不要设置状态。
this.state
内部的setState
被禁止,只能“偶然”工作。
答案 1 :(得分:0)
第一个循环的问题是您每次迭代都覆盖现有项目,并且由于setState是异步的,因此这样做是不安全的
为什么不这样做呢?
onFileSelect = e => {
//FileList to array
const files = [...e.target.files];
this.setState({ invoices: []})
files.each(file => this.state.invoices.push(file)});
}
答案 2 :(得分:0)
第二个选项似乎是正确的。
如果要返回新数组,则应使用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});
}