파일을 여러개 각각 업로드 해야할 때,
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;
// 파일 세 개의 경로(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에 붙인다.