I am trying to mock progress bar for each file that are selected and stored in array. I want to individually track the progresses of each file ( i am using setInterval for mock purposes). Right now I am having a single button that uses same tracker value for all files when I click. Can someone help how to use individual timers for each element in the array.
Code
import * as React from "react";
import { Button, Stack, List, ListItem } from "@material-ui/core";
import { useState, useRef } from "react";
import { Progress } from "./Progress";
import DeleteIcon from "@mui/icons-material/Delete";
interface UploaderProps {
fileType?: string | AcceptedFileType[];
}
interface IFile {
file: File;
uploadProgress: number;
uploadError: string;
}
export const Upload = (props: UploaderProps) => {
const [selectedFiles, setSelectedFiles] = useState<
IFile[] | undefined | null
>([]);
const [progress, setProgress] = useState<number>(0);
const timerRef = useRef<ReturnType<typeof setInterval> | undefined>();
const filterBy = (key: string, set = new Set()) => (o: any) =>
!set.has(o[key]) && set.add(o[key]);
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
setProgress(0);
const currentSelected: File[] = Array.prototype.slice.call(
event?.target?.files
);
const filtered: File[] = [
...(selectedFiles || []),
...currentSelected
].filter(filterBy("name"));
setSelectedFiles(filtered);
};
const onFileUpload = () => {
timerRef.current = setInterval(() => {
setProgress((oldProgress) => {
if (oldProgress === 100) {
clearInterval(timerRef?.current);
setSelectedFiles([]);
return oldProgress;
}
const diff = Math.random() * 15;
return Math.min(oldProgress + diff, 100);
});
}, 500);
};
return (
<>
<Button
variant="contained"
component="label"
style={{ textTransform: "none" }}
>
<input
hidden
type="file"
multiple
accept={acceptedFormats}
onChange={handleFileSelect}
/>
{!selectedFiles?.length && <span> Choose file to upload</span>}
<List>
{!!selectedFiles?.length &&
selectedFiles?.map(({ name, size }) => (
<ListItem key={name}>
<span className="primary">{name}</span>
<span style={{ paddingLeft: "5px" }}>({size})</span>
<Stack style={{ paddingLeft: "10px", width: "100px" }}>
<Progress {...{ progress }} />
</Stack>
<Button onClick={onFileUpload}>Upload</Button>
<DeleteIcon
onClick={(e: any) => {
e.preventDefault();
setSelectedFiles(
selectedFiles.filter((file: File) => file.name !== name)
);
}}
/>
</ListItem>
))}
</List>
</Button>
{!!selectedFiles?.length && (
<div>
<Button>Clear All</Button>
</div>
)}
</>
);
};
Sandbox: https://codesandbox.io/s/react-hook-upload-oxqdp2?file=/src/Upload.tsx:0-3474