我们要并行发布多个文件并显示上传进度。
我们解决该问题的第一个尝试是在setupProgress回调中使用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个文件。
正确的方法是什么?到目前为止,我们有2个工作示例:
1)解决方案1
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
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} />
</>
);
};
欢迎提供针对此特定案例的最佳实践的任何反馈或工作示例。
谢谢
答案 0 :(得分:2)
您不能在响应回调中使用未决的const,因为它将引用一个过时的版本。而是考虑使用以前的状态setState签名,例如:setPendingUploads((prevPendingUploads) => {return {...prevPendingUploads, /* updates here */}}