按顺序运行计时器:Reactjs



我有一个文件上传组件,它接收要上传的文件列表。I我实现的wau,每个文件都有三个定时器并行运行,而不会影响其他文件。进度条附在每个文件上,并以并行方式运行到完成。我想要的是,一旦我选择了文件,我希望每个文件都以顺序的方式运行其进度条,而不是同时运行所有进度条。比如拿一个文件,运行它的进度,然后完成后,转到下一个

有人能帮助吗

https://codesandbox.io/s/updated-file-upload-4vrnks?file=/src/Upload.tsxfile=/src/Upload.tsx:0-3474

import * as React from "react";
import { Stack, Button, ListItem } from "@material-ui/core";
import { useEffect, useRef } from "react";
import { Progress } from "./Progress";
export interface FileType {
file: File;
isDeleted: boolean;
uploadStatus: number;
uploadError: string;
uploadAbort: boolean;
}
interface FileUploaderProps {
selectedFiles: FileType[];
setSelectedFiles: React.Dispatch<React.SetStateAction<FileType[]>>;
file: FileType;
}
const UploadFile = ({ file, setSelectedFiles }: FileUploaderProps) => {
const timerRef = useRef<ReturnType<typeof setInterval> | undefined>();
const pollRef = useRef<number>();
pollRef.current = file.uploadStatus;
const onFileUpload = () => {
timerRef.current = setInterval(() => {
if (pollRef.current === 100) {
clearInterval(timerRef?.current);
return pollRef?.current;
}
const diff = Math.random() * 15;
let currentProgess = file.uploadStatus;
setSelectedFiles((prevState) => {
return prevState.map((current: FileType) => {
if (current.file.name === file.file.name) {
currentProgess = Math.min(current.uploadStatus + diff, 100);
return {
...current,
uploadStatus: currentProgess
};
}
return current;
});
});
return currentProgess;
}, 100 * Math.floor(Math.random() * 6) + 5 * 50);
};
useEffect(() => {
onFileUpload();
return () => {
clearInterval(timerRef.current);
};
}, []);
const cancelTimer = (e: React.MouseEvent<HTMLSpanElement>) => {
e.stopPropagation();
setSelectedFiles((prevState) => {
return prevState.map((current: FileType) => {
if (current.file.name === file.file.name) {
return {
...current,
uploadAbort: true,
uploadStatus: 0,
uploadError: "File Upload cancelled"
};
}
return current;
});
});
clearInterval(timerRef.current);
};
return (
<ListItem key={file.file.name} className={"file-name"}>
<span style={{ padding: "10px" }}>{file.file.name}</span>
{file.uploadStatus !== 100 ? (
file.uploadError || file.uploadAbort ? (
<div className={"upload-error"}>
<span>{file.file.name}</span>
<span style={{ padding: "10px" }}>{file.uploadError}</span>
</div>
) : (
<>
<span>Uploading...</span>
<Stack sx={{ width: "80px", padding: "20px" }} spacing={2}>
<Progress progress={file.uploadStatus} />
</Stack>
<Button variant="contained" color="error" onClick={cancelTimer}>
Cancel
</Button>
</>
)
) : (
<>
<span className="primary">{file.file.name}</span>
</>
)}
{file.uploadStatus === 100 && (
<Button
variant="contained"
color="error"
className="mgmt-Delete-icon"
style={{ padding: "10px" }}
onClick={(e: React.MouseEvent<HTMLSpanElement>) => {
e.stopPropagation();
setSelectedFiles((prevState) => {
return prevState.map((current: FileType) => {
if (current.file.name === file.file.name) {
return {
...current,
isDeleted: true
};
}
return current;
});
});
}}
>
Delete
</Button>
)}
</ListItem>
);
};
export default UploadFile;

让我们将active属性添加到FileType:

export interface FileType {
...
active: boolean;
}

默认情况下,所有删除的文件都处于非活动状态。

当文件变得活动:时,我们希望开始上传

useEffect(() => {
if (file.active) {
onFileUpload();
}
return () => {
clearInterval(timerRef.current);
};
}, [file.active]);

每当selectedFiles更改时,我们都会选择下一个活动文件(或保持最新(:

useEffect(() => {
const newActiveFile = selectedFiles.find(
(f) =>
!f.isDeleted &&
!f.uploadAbort &&
!f.uploadError &&
f.uploadStatus !== 100
);
if (newActiveFile && !newActiveFile.active) {
setSelectedFiles(
selectedFiles.map((f) =>
f === newActiveFile ? { ...newActiveFile, active: true } : f
)
);
}
}, [selectedFiles]);

工作示例

更新

您可以通过将此筛选器添加到List:来隐藏未启动的文件

&& file.active

更新的示例

最新更新