setState 在 Array.map 函数中只执行一次



我有一个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 个文件,则只有最后一个文件进入该状态。

一个可能的解决方案是获取exesting数组,推送新文件并在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});
}

这是因为 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});
}

最新更新