[Web API] FileReader & FormData

dosilv·2021년 6월 6일
7

🧪 구현하고자 하는 기능

이미지 파일을 업로드받기 위해 input type="file"을, 업로드된 파일을 미리보기로 표시하기 위해 FileReader API를 사용했다. 그리고 이미지 파일과 일반 string 데이터를 함께 서버로 전송하기 위해 FormData API를 사용함!



🧪 input type="file"

input type은 text, password, number, range... 이런 것만 써왔는데, file 이라는 타입도 있다는 걸 이번에 배우게 되었다. type="file"로 설정하면 자동으로 파일 선택 버튼이 생기고, 클라이언트로부터 파일을 업로드 받을 수 있다! multiple 속성을 주면 여러 파일 업로드도 가능~~

<input type="file" accept="받을 파일 종류" />

여기에 onClick={e => {console.log(e)}로 이벤트를 출력해 보면 필요한 속성들을 얻을 수 있음!

🎾 input[type="file"]이 가지는 property

  • e.target.value: 파일의 경로(string) - 보안상 C:\\fakepath\\파일명으로 표시됨
  • e.target.files: 파일 정보를 담은 File 객체를 담은 FileList 객체!
    0: File, 1: File, 이런 식으로 떠서 처음에는 배열인 줄 알았는데, 0, 1, 2, ...(업로드된 파일 수만큼), 그리고 length를 key로 가지는 object였음! 아무것도 업로드 하지 않을 경우 {length: 0}.
  • e.target.accept: 업로드할 수 있는 파일 종류

    다른 타입의 input들은 e.target.value가 중요하지만 file의 경우 value는 경로(string)에 불과하고, 실제 파일 정보를 담은 오브젝트인 e.target.files가(특히 e.targtet.files[0]!) 아주 많이 쓰인다.


🧪 FileReader API

위 input으로 업로드 받은 이미지를 미리보기로 화면상 띄우기 위해 사용할 수 있는 것이 FileReader API! 업로드 받은 건 파일 형태이고, 화면에 표현하기 위해서는 url 주소가 필요한데, FileReaderAPI의 readAsDataURL() 메서드로 서버 업로드 전에 미리 url 주소를 사용할 수 있다~~!

🎾 적용한 코드

url을 얻기 위해 readURL이라는 함수를 만들었다. input의 onChange시에 실행할 것!

const readURL = e => {
  if (e.target.files.length) {
    const reader = new FileReader();
    reader.readAsDataURL(e.target.files[0]);
    reader.onload = function (e) {
      setPreviewImg(e.target.result);
    };
  }
};

line by line으로 분석해 보면

  • if (e.target.files.length)
    업로드된 파일이 있는지 여부를 체크하는 조건문
  • const reader = new FileReader()
    if문을 톻과하면 새로운 FileReader 객체를 생성한다
  • reader.readAsDataURL(e.target.files[0])
    reader에게 e.target.files[0](업로드된 파일)를 URL로 읽으라고 명령!
  • reader.onload = function (e)
    읽기 동작이 성공적으로 load되었을 때 발생할 이벤트 핸들러
  • setPreviewImg(e.target.result);
    previewImg라는 state 변수에 읽어낸 결과값(URL)을 담아 줌!

그리고 이 previewImg를 원하는 img 요소의 src 속성값으로 넣어주면 사용자가 이미지를 올렸을 때 미리보기로 출력된다~~!



🧪 FormData API

프리뷰와 별개로, 업로드 받은 이미지를 서버에 전송하려면 FormData API를 사용할 수 있음! 특히 이번에는 썸네일용 이미지 파일과 기타 정보(텍스트 형태)가 담긴 오브젝트를 함께 전송해야 했는데, 그러려면 얘네를 formdata에 묶어서 보내야 했다. (GOD유진님의 도움으로 알게됨...✨)

🎾 적용한 코드

  1. input으로부터 이미지 파일 가져오기
<input type="file" accept="image/*" onChange={e => {setThumbnail(e.target.files[0])}} required />

thumbnail이라는 state 변수에 담아주었다!

  1. 함께 보낼 다른 타입의 정보(string, object 등) JSON.stringify() 해 주기
const classInfo = JSON.stringify({
  title: title,
  sub_category: values.subCategory.id,
  ...
});

파일은 stringify를 해 주면 안 돼서 따로 처리해 주는 것!

  1. 새로운 FormData 생성하고, 거기에 append 메서드로 데이터 추가해 주기
const classData = new FormData();
classData.append('course', classInfo);
classData.append('image', thumbnail);

append의 첫 번째 인자는 백엔드와 맞춰야하는 key값이고, 두 번째 인자가 각각의 데이터에 해당한다.

  1. body에 담아 서버에 전송~~~!
fetch(`${API}/courses/register`, {
        method: 'POST',
        headers: {
          Authorization: localStorage.getItem('access_token'),
        },
        body: classData,
      })


신기하고 유용한 API가 정말 정말 많은 것 같다.🍀🍀



🙇‍♀️ 참고한 자료

File API 정리하기
FormData - Web API | MDN

profile
DevelOpErUN 성장일기🌈

0개의 댓글