file upload, download

·2023년 1월 11일
0

파일을 여러개 각각 업로드 해야할 때,

업로드 버튼 한 개

import axios from 'axios';
import React, { useEffect, useRef, useState } from 'react';

const FileLoad = () => {
  const [file, setFile] = useState();
  const [fileName, setFileName] = useState();
  const [fileArr, setFileArr] = useState([]);
  const [allFile, setAllFile] = useState([]);

  // 파일 업로드
  const handleSubmit = async (e) => {
    e.preventDefault();

    const formdata = new FormData();
    formdata.append('키',);
    formdata.append('키',);
    ...
    
    try {
      await axios.post(
        'http:// 파일 업로드 api 주소 ',
        formdata,
        { headers: { 'Content-Type': 'multipart/form-data' } },
      );
      location.reload(); // 새로고침
    } catch (error) {
      console.log(error);
    }
  };
  
  // 파일 리스트
  useEffect(() => {
    const data = { api요구 '키':};
    const fetchData = async () => {
      try {
        const res = await axios.post(
          'http:// 파일 리스트 api 주소 ',
          data,
          { headers: { 'Content-Type': 'application/json' } },
        );

        setAllFile(res.data);
      } catch (error) {
        console.error();
      }
    };
    fetchData();
  }, []);
  
  const handleClick = (e) => {
    setFile(e.target.files[0]);
    setFileName(e.target.files[0].name);
  };
  
  return(
   <>
  	<form onSubmit={handleSubmit}>
      <input type="file" onChange={handleClick} />
      <button type="submit">버튼</button>
    </form>
    {allFile.length &&
      allFile.map(file => {
        return (
          <ul key={file}>
            {file.split('/')[1] ? (
              <li>{file.split('/')[1]}</li>
            ) : (
              <li>파일명 : {file.split('/')[0]}</li>
            )}
          </ul>
        );
      })}
   </>
  );
};

export default FileLoad;

업로드 버튼 한 개 이상

  • 조건 : form제출 시 파일 세 개를 같이 제출.
    단, 하나의 업로드 버튼에서 세 개의 파일을 업로드하는 것이 아닌, 세 개의 업로드 버튼에서 각각 하나의 파일만 업로드한다.
// 파일 세 개의 경로(Root)와 이름(Name)을 하나의 state에서 객체로 관리
const [fileRoot, setFileRoot] = useState({
  fileOne:'',
  fileTwo:'',
  fileThree:''
})
const [fileName, setFileName] = useState({
  fileOne:'',
  fileTwo:'',
  fileThree:''
})

// 파일 업로드
const handleFileUpload = async (e) => {
    e.preventDefault();

    let formdata = new FormData();
     formdata.append('키',);
     formdata.append('키',);

    try {
      const res = await axios.post(
        'http:// 파일 업로드 api주소 ',
        formdata,
        { headers: { 'Content-Type': 'multipart/form-data' } },
      );

      setFileRoot(fileRoot => ({ // fileRoot나 prevState로 설정해도 결과는 똑같다.
        ...fileRoot,
        [e.target.className]: res.파일의 경로값,
      }));

      setFileName(prevState => ({ // fileName이나 prevState로 설정해도 결과는 똑같다.
        ...prevState,
        [e.target.className]: res.파일의 이름,
      }));
    } catch (error) {
      console.log(error);
    }
  };


// 파일 다운로드
const handleFileDownload = async (e) => {
    try {
	  const data = {'키':};
      const res = await axios.post(
        'http:// 파일 다운로드 api 주소 ',
        data,
        {
          headers: {},
          responseType: 'blob',
        },
      );
'downloadRes');
      const extractDownloadFilename = res => {
        const disposition = res.headers['content-disposition'];
        const fileName = decodeURI(
          disposition
            .match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1]
            .replace(/['"]/g, ''),
        );
        return fileName;
      };
      const blob = new Blob([res.data]);
      const fileObjectUrl = window.URL.createObjectURL(blob);

      const link = document.createElement('a');
      link.href = fileObjectUrl;
      link.style.display = 'none';
      link.download = extractDownloadFilename(res);

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

    } catch (error) {
      console.log(error);
    }
  };

return(
  <>
  	<div> // -----------------------------------파일1업로드,다운로드
  	  <div>파일 1</div>
  	  <label htmlFor='file1'>
  	    <input 
  		  type='file'
  		  name='file1' 
  		  className='fileOne'
  		  onChange={e=>handleFileUpload(e)} 
		  style={{ display: 'none' }}
	    />
  	    <button>
  		  파일올리기
  	    </button>
      </label>
  	  <div 
		onClick={e=>handleFileDownload(e)}
       >
  	    {fileOne} 업로드 한 파일 내려받기
  	  </div>  
  	</div>
	<div> // -----------------------------------파일2업로드,다운로드
  	  <div>파일 2</div>
  	  <label htmlFor='file2'>
  	    <input 
  		  type='file'
  		  name='file2' 
		  className='fileTwo'
  		  onChange={e=>handleFileUpload(e)} 
		  style={{ display: 'none' }}
	    />
  	    <button>
  		  파일올리기
  	    </button>
      </label>
  	  <div 
		onClick={e=>handleFileDownload(e)}
       >
        {fileTwo} 업로드 한 파일 내려받기
  	  </div>            
    </div>
	<div> // -----------------------------------파일3업로드,다운로드
  	  <div>파일 3</div>
  	  <label htmlFor='file3'>
  	    <input 
  		  type='file'
  		  name='file3'
		  className='fileThree'
  		  onChange={e=>handleFileUpload(e)} 
		  style={{ display: 'none' }}
	    />
  	    <button>
  		  파일올리기
  	    </button>
      </label>
  	  <div 
		onClick={e=>handleFileDownload(e)}
       >
  	    {fileThree} 업로드 한 파일 내려받기
  	  </div>            
    </div>
  </>
);
  • 업로드 설명
    -각각의 업로드 할 파일버튼을 생성.
    -하나의 함수handleFileDownload에서 업로드를 처리.
    -onChange시 호출되는 함수에 event를 props로 넘겨준다. 넘겨 받은 함수에서 className을 검색하여, 변수를 선언한 객체의 키값이 className과 같으면 키값과 값을 저장한다.
    -spread 문법을 사용하였다.

  • 다운로드 설명
    -파일 다운로드도 업로드와 같다.
    -다운로드에서 중요한 부분은 blob이다.
    -파일 이름으로 다운로드하기 위해서는 content-disposition값을 가져와서 디코딩을 필수로 거쳐야한다.
    -필요한 부분을 정규표현식(regex)과 replace로 추출한다.
    -new Blob() 생성자를 사용하여 유형이 지정된 배열에서 blob을 만들 수 있다.
    -window.URL.createObjectURL()을 사용하여 url을 생성한다.
    -<a>태그를 생성하여 attribute를 설정한다.
    -설정된 <a>태그를 document.body에 붙인다.

Spread 문법(...)이란?

  • ECMAScript6(2015)에서 새로 추가된 문법이다. 문법 이름처럼 객체 혹은 배열들을 펼칠 수 있게 해준다.
  • ES6의 Spread 문법(…)을 사용한 배열을 인수로 함수에 전달하면 배열의 요소를 분해하여 순차적으로 파라미터에 할당한다.
  • 반복 가능한 객체 (Iterable Object)를 개별 요소로 분리할 수 있다.
  • rest문법과 형태는 똑같으나, 사용이 다르다.

profile
어두운 밤하늘, 밝은 달빛.

0개의 댓글