我们希望并行发布多个文件并显示上传进度。
我们解决这个问题的第一次尝试是在uploadProgress回调中使用setState和以前的状态:
const FileUpload = () => {
const [pendingUploads, setPendingUploads] = useState({});
// For clarity: files = Record<string, {id: string, progress: string, data: FormData}>
const handleChange = files => {
setPendingUploads(files);
const handleUploadProgress = (progressEvent, id) => {
const percentCompleted = (progressEvent.loaded * 100) / progressEvent.total;
// Problem: pendingUploads is always empty, we do not get the updated value from last update
setPendingUploads({
...pendingUploads,
[id]: {
...pendingUploads[id],
progress: `${percentCompleted}%`
}
});
};
files.forEach(file => {
axios.post("/files", file.data, {
onUploadProgress: e => handleUploadProgress(e, file.id)
});
});
};
return (
<>
<div>
{_.map(pendingUpload, (pendingUpload, idx) => (
<div key={idx}>
{pendingUpload.id}: {pendingUpload.progress}
</div>
))}
</div>
<input multiple type="file" onChange={handleChange} />
</>
);
};
pendingUploads始终为空,因此一次只显示1个文件的进度值。
正确的方法是什么?到目前为止,我们有两个工作示例:
1(解决方案1
- 保持挂起上传的映射处于状态(pendingUploads(
- 使用handleUploadProgress(axios回调(内的setState触发进度更新(progressUpdate(
- 更新挂起使用中的上传进度时效果更新更改
const FileUpload = () => {
const [pendingUploads, setPendingUploads] = useState({});
const [progressUpdate, setProgressUpdate] = useState({ id: "", value: "" });
useEffect(() => {
setPendingUploads({
...pendingUploads,
[progressUpdate.id]: {
...pendingUploads[progressUpdate.id],
progress: progressUpdate.value
}
});
}, [progressUpdate]);
const handleUploadProgress = (progressEvent, id) => {
const percentCompleted = (progressEvent.loaded * 100) / progressEvent.total;
setProgressUpdate({ id, value: `${percentCompleted}%` });
};
// files = Record<string, {id: string, progress: string, data: FormData}>
const handleChange = files => {
setPendingUploads(files);
files.forEach(file => {
axios.post("/files", file.data, {
onUploadProgress: e => handleUploadProgress(e, file.id)
});
});
};
return (
<div>
<div>
{_.map(pendingUploads, (pendingUpload, idx) => (
<div key={idx}>
{pendingUpload.id}: {pendingUpload.progress}
</div>
))}
</div>
<input multiple type="file" onChange={handleChange} />
</div>
);
};
2(解决方案2
- 在uploadProgress回调中更改文件,并使用更改后的值更新组件的状态
const FileUpload = () => {
const [pendingUploads, setPendingUploads] = useState({});
// files = Record<string, {id: string, progress: string, data: FormData}>
const handleChange = files => {
const handleUploadProgress = (progressEvent, id) => {
const percentCompleted = (progressEvent.loaded * 100) / progressEvent.total;
files[id].progress = `${percentCompleted}%`;
setPendingUploads({ ...files });
};
files.forEach(file => {
axios.post("/files", file.data, {
onUploadProgress: e => handleUploadProgress(e, file.id)
});
});
};
return (
<>
<div>
{_.map(pendingUpload, (pendingUpload, idx) => (
<div key={idx}>
{pendingUpload.id}: {pendingUpload.progress}
</div>
))}
</div>
<input multiple type="file" onChange={handleChange} />
</>
);
};
欢迎提供任何反馈或工作示例,以展示该特定案例的最佳实践。
感谢
您不能在响应回调中使用pendingUploads const,因为它将引用过时的版本。相反,考虑使用以前的状态集状态签名,如:setPendingUploads((prevPendingUploads) => {return {...prevPendingUploads, /* updates here */}}