본문 바로가기
개발/React

React Material - 파일 다운로드 경과 로딩 과정 보여주기 (Mui Loading Circular Progress with File Download)

by 피로물든딸기 2023. 7. 9.
반응형

리액트 전체 링크

 

참고

- 파일 브라우저에서 파일 다운로드하기

- 비동기 함수 로딩 중 보여주기

- 파일 다운로드 경과 확인하기

 

파일 다운로드 경과 확인하기에서 로그로 출력하였던 내용을 

비동기 함수 로딩 바 보여주기에서 사용한 ModalCircular Progress에 적용해보자.

percentageuseState로 관리하는 코드를 추가하고, finallyModal을 닫도록 설정하면 된다.

  axios
    .get(`http://192.168.55.120:3002/downloadFile?filePath=${filePath}`, {
      responseType: "arraybuffer",
      onDownloadProgress: (event) => {
        const per = Math.round((event.loaded * 100) / event.total);

        console.log(`${event.loaded} / ${event.total} ${per}`);
        setProgress(per); // progress bar
      },
    })
    .then((res) => {
      downloadPC(res, "download.zip");
    })
    .catch((error) => console.log(error))
    .finally(() => setOpen(false)); // 완료 후 모달 닫기

 

그리고 ModalCircular Progress를 추가하면 된다.

  <Modal
    open={open}
    aria-labelledby="modal-modal-title"
    aria-describedby="modal-modal-description"
  >
    <Box sx={style}>
      <CircularProgressWithLabel value={progress} />
    </Box>
  </Modal>

 

이제 파일을 다운로드하면 다운로드 경과 내용이 Circular Progress로 확인할 수 있다.

 

전체 코드는 다음과 같다.

import React, { useState } from "react";

import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Modal from "@mui/material/Modal";
import Typography from "@mui/material/Typography";
import CircularProgress from "@mui/material/CircularProgress";

import axios from "axios";

function CircularProgressWithLabel(props) {
  return (
    <Box sx={{ position: "relative", display: "inline-flex" }}>
      <CircularProgress variant="determinate" {...props} />
      <Box
        sx={{
          top: 0,
          left: 0,
          bottom: 0,
          right: 0,
          position: "absolute",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        <Typography variant="caption" component="div" color="text.secondary">
          {`${Math.round(props.value)}%`}
        </Typography>
      </Box>
    </Box>
  );
}

const App = () => {
  const [open, setOpen] = useState(false);
  const [progress, setProgress] = useState(0);

  const style = {
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    width: "100%",
    height: "100%",
    bgcolor: "rgba(255,255,255,0.5)",
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
  };

  const downloadPC = (response, fileName) => {
    const url = window.URL.createObjectURL(
      new Blob([response.data], { type: `${response.headers["content-type"]}` })
    );

    let link = document.createElement("a");
    link.href = url;
    link.setAttribute("download", fileName);

    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);

    window.URL.revokeObjectURL(url);
  };

  const downloadFile = () => {
    let filePath = "D://download.zip";

    setOpen(true);

    axios
      .get(`http://192.168.55.120:3002/downloadFile?filePath=${filePath}`, {
        responseType: "arraybuffer",
        onDownloadProgress: (event) => {
          const per = Math.round((event.loaded * 100) / event.total);

          console.log(`${event.loaded} / ${event.total} ${per}`);
          setProgress(per);
        },
      })
      .then((res) => {
        downloadPC(res, "download.zip");
      })
      .catch((error) => console.log(error))
      .finally(() => setOpen(false));
  };

  return (
    <div>
      <Button variant="outlined" onClick={downloadFile} sx={{ m: 2 }}>
        File Download
      </Button>
      <Modal
        open={open}
        aria-labelledby="modal-modal-title"
        aria-describedby="modal-modal-description"
      >
        <Box sx={style}>
          <CircularProgressWithLabel value={progress} />
        </Box>
      </Modal>
    </div>
  );
};

export default App;
반응형

댓글