Call setinterval for each item in the array

Viewed 38

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

0 Answers
Related