javascript - 异步函数应仅更新一项时覆盖数组状态
问题描述
我有一个文件上传组件。行为很简单:我向每个文件的后端发送一个上传请求,随着上传进度的增加,我有一个应该随之增加的栏。
我有一个包含每个选定文件及其各自进度的状态,例如:
interface IFiles {
file: File;
currentProgress: number;
}
const [selectedFiles, setSelectedFiles] = useState<IFiles[]>([]);
并且当用户点击上传按钮时,该函数将被触发并调用uploadFile
我数组状态下的每个文件。
const sendFilesHandler = async () => {
selectedFiles.map(async (file) => {
const fileType = file.file.type.split('/')[0];
const formData = new FormData();
formData.append(fileType, file.file);
formData.append('filename', file.file.name);
await uploadFile(formData, updateFileUploadProgress);
});
};
这是uploadFile
函数的样子。
const uploadFile = async (body: FormData, setPercentage: (filename: string, progress: number) => void) => {
try {
const options = {
onUploadProgress: (progressEvent: ProgressEvent) => {
const { loaded, total } = progressEvent;
const percent = Math.floor((loaded * 100) / total);
const fileName = body.get('filename')!.toString();
if (percent <= 100) {
setPercentage(fileName, percent)
}
}
};
await axios.post(
"https://nestjs-upload.herokuapp.com/",
body,
options
);
} catch (error) {
console.log(error);
}
};
如您所见,当 uploadProgress 被触发时,它应该通知调用 setPercentage 函数,即:
const updateFileUploadProgress = (fileName: string, progress: number) => {
console.log('Entrada', selectedFiles);
const currentObjectIndex = selectedFiles.findIndex((x) => fileName === x.file.name);
const newState = [...selectedFiles];
newState[currentObjectIndex] = {
...newState[currentObjectIndex],
currentProgress: progress,
};
setSelectedFiles(newState);
console.log('Saída', newState);
};
这个函数应该只更新我的状态数组中文件名匹配的对象。然而,它压倒了整个事情。行为如下:
因此,只要我更新同一个对象,似乎一切都很好。onUploadProgress
但是在被触发到另一个对象的那一刻,selectedFiles
状态又变成了它的初始状态。为了使这项工作正常工作,我缺少什么?
解决方案
我不确定这种行为背后的确切原因是什么,但在花了 3 个小时之后,我想出了以下出人意料的简单解决方案。
const updateFileUploadProgress = (fileName: string, progress: number) => {
setSelectedFiles(prevState => {
const currentObjectIndex = prevState.findIndex((x) => fileName === x.file.name);
const newState = [...prevState];
newState[currentObjectIndex] = {
...newState[currentObjectIndex],
currentProgress: progress,
};
return newState;
})
};
我能够在本地模仿您的问题,并用上述方法解决了它。我认为这是因为该函数(出于某种原因)即使在重新渲染之后仍然引用了初始状态。
推荐阅读
- bash - tr 命令:| 的奇怪行为 和 \
- django - 提高 Django 登录安全性和密码强度
- python - 取消设置或关闭某些属性的当前模块
- c# - 无法让控制台日志记录在 .net core 2.0 中工作
- java - 检查所有 ListView CheckBoxes 时如何触发 JavaFX 事件?
- ruby - Google Analytics API ruby 客户端 - 多个指标
- google-analytics - Google Analytics 事件 - 日期范围值
- javascript - 从范围输入中检索实时值以在另一个函数中使用
- awk - AWK (igawk) @include 语句失败
- python - 由于 AttributeError,在 PyCharm 中导入 matplotlib.pyplot 失败:模块“PyQt5.QtGui”没有属性“QApplication”