[TIL] 멀티 업로드 및 File to dataUrl

Solmin Seo·2021년 3월 15일
0
post-thumbnail

배경

input type=file 을 이미지 업로드과 Filelist의 0번째의 파일에 접근하여 dataUrl로 parsing 까지는 마쳐놓은 상태였지만 사용자 편의성을 위해 작성해놓은 로직에 멀티업로드를 추가하는 작업이 필요했다.

dataUrl이란?

이미지를 업로드 후 해당 이미지를 브라우저에서 업로드 한 내용을 보여주려면 File 자체로는 보여줄 수 없다. 여러 방법 중 dataUrl을 사용하는 방법을 사용해보려한다. 개인적으로는 css에서 background-image: url() 안에 들어갔었던 dataUrl이라고 생각했더니 어떤것인지 이해가 쉬웠다.

단계 (설계)

작업을 진행하기 전 단계를 나누어 보았다.

  1. input 에서 여러개의 이미지 파일을 선택
  2. event에 전달된 FileList의 각각의 file을 추출
  3. 추출된 개별의 File을 dataUrl로 변환
  4. 컴포넌트에서 관리중인 state에 저장

문제점

  • 단계를 보았을때에는 정말 쉬워보였지만 fileReader 의 동기처리, 기존 array와는 다른 fileList 핸들링이 익숙치 않아 어려움을 겪었었다.
  1. fileList는 기존 배열과 달라 map, forEach, shift 등을 사용할 수 없었다.
  2. useState의 set함수는 비동기이기때문에 map 안에서 제대로 작동하지 않았다. 새로운 변수에 담은 다음 가장 마지막에 set을 하는게 좋아보였다.

구현 단계

  1. 여러개의 파일을 dataUrl로 변환하고 저장할 배열을 만들어야한다. 허나 fileReader는 하나의 작업을 마쳐야 다음으로 넘어갈 수 있기때문에 promise로 만들어야했다.

  2. dataUrl로 변환된 배열이 만들어지면 해당 배열을 돌면서 새로운 객체를 만들어 리턴해주었다.

  3. 마지막 useState의 set함수를 이용하여 state에 반영해주었다.

  4. 똑같은 이미지를 연속으로 넣었을때에 React는 같은 값으로 인지하기에 렌더링 및 state변화가 일어나지 않았던것 같다. 맞는 방법인지는 모르겠으나, e.target.value = '' 를 활용해서 값을 계속 비워주었다.

완성된 코드

const readFile(file: File) => {
 return new Promise((resolve) => {
   const rader = new FileReader();
   reader.addEventListener('load' () => resolve(reader.result), false);
 })
}

const makeDataUrl = (files: FileList) => {
 return Promise.all(Array.from(files).map((v) => readFile(v))) 
}

const uploadImages = async (e) => {
  try {
    const dataUrl = await makeDataUrl(e.target.files);
    const newData = dataUrl.map((v) => {
      increasingRefId.current += 1;
      return {
        sampleData1: increasingRefId.current,
        samplePreviewDataUrl: v,
      };
    });

    setSampleState({
      ...sampleState,
      sampleImgArray: [...sampleState.sampleImgArray, ...newData],
    });
  } catch (error) {
    console.log(error);
  }
  e.target.value = '';
};
profile
코린이

0개의 댓글