업무 진행 중, React에서 image를 업로드 해야 할 일이 생겨 정리해보았다.
image는 file이기 때문에, input 태그를 사용하여 업로드 할 수 있다.
<div>
<input type='file'
accept='image/jpg,impge/png,image/jpeg,image/gif'
name='profile_img'
onChange={onChange}>
</input>
</div>
accept
는 업로드 할 수 있는 파일 확장자이다. 어진 파일 유형의 식별 방법이 여러 가지일 수도 있으므로, 특정 파일 형식이 필요할 땐 유형의 집합을 제공하는 것이 좋다.
file 타입 input의 value
는 선택한 파일의 경로를 나타내는 DOM String을 담고 있다. 여러 개의 파일을 선택한 경우, 첫 번째 파일을 가리킨다. 나머지 파일 요소는 HTMLInputElement.files 속성으로 가져올 수 있다.
다음과 같이 파일을 입력받아 FormData
객체에 집어넣어 파일을 손쉽게 전송할 수 있다.
const onChange = (e) => {
const img = e.target.files[0];
const formData = new FormData();
formData.append('file', img);
}
MDN 문서에 FormData
인터페이스는 form 필드와 그 값을 나타내는 일련의 key/value 쌍을 쉽게 생성할 수 있는 방법을 제공합니다. 라고 쓰여있다.
다시말하면formData
는 내가 지정한 key값과 파일을 value로 삼아 데이터 및 파일 전송을 손쉽게 해주는 객체이다.
기존의 formData
가 없었을 때는, 서버로 복합적인 데이터를 보내기 위해 multipart/form-data
를 사용해야 했다.
multipart/form-data
는 파일 업로드가 있는 양식요소에 사용되는 enctype 속성의 값중 하나이고, multipart는 폼데이터가 여러 부분으로 나뉘어 서버로 전송되는 것을 의미한다.
<form method="post" enctype="multipart/form-data" action="http://foo.bar/upload">
<input type="file" name="media"/>
<input name="nickname"/>
<input name="website"/>
<input type="submit" value="upload"/>
</form>
하지만 formData
를 통해 form
을 생성하지 않고 손쉽게 파일을 전송할 수 있게 되었다.
const onChange = (e) => {
const img = e.target.files[0];
const formData = new FormData();
formData.append('img', img);
console.log(formData) // FormData {}
for (const keyValue of formData) console.log(keyValue); // ["img", File] File은 객체
}
다시 onChange
함수로 돌아가서, console.log(formData)
에 빈 객체가 찍히는 이유는 FormData
는 XMLHtpRequest를 사용하여 전송할 키/값 쌍 집합을 컴파일한 특수한 객체이기 때문에, 문자열로 표현할 수 없기 때문이다.
그렇기 때문에, FormData
의 요소를 확인하려면, 객체를 반복시키는 루프 for ... of
로 내부를 확인해 볼 수 있다.