리액트에서 이미지 업로더 구현하기

이인송·2021년 7월 16일
1
post-thumbnail

🙋‍♂️ 들어가기

  1. 파일선택 Input 만들기
  2. 선택된 파일 읽기
  3. 파일 전송하기

👨‍💻이해하기

팀 프로젝트에서 이미지 업로더를 구현 기능을 맡았다.
크게 미리보기 기능과 파일 전송 기능으로 나눠서 기능을 구현했다.

1. 파일 선택 Input 만들기

<input type="file />

여기까지 하면 아래와 같이 데스크탑에서 파일을 선택할 수 있는 버튼이 생성된다.

2. 선택된 파일 읽기

일반적인 Input 태그에 입력된 값을 확인하는 것처럼
onChange 속성에 함수를 작성하여 event.target.files 를 확인할 수 있으며,
이를 서버에 전송하고, 사용자에게 미리보기를 제공하기위해 state 에 저장해야한다.

const [imgfile, setImage] = useState('');

그리고나서 두 가지 함수와 return 하는 형태를 알아보자

  1. 파일로부터 이미지를 읽어오는 함수
  2. 이미지 미리보기를 만드는 함수
  3. return 되는 형태

  1. 파일로부터 이미지를 읽어오는 함수
const setImageFromFile = ({ file, setImageUrl }) => {
    let reader = new FileReader();
    reader.onload = () => {
      setImageUrl({ result: reader.result });
    };
    reader.readAsDataURL(file);
  }

  1. 이미지 미리보기를 만드는 함수
const createImagePreview = e => {
    const files = e.target.files;
    if (files.length) {
      setImageFromFile({
        file: files[0],
        setImageUrl: ({ result }) => {
          setImage(files[0]);
        },
      });
    }
  };

  1. return 되는 형태
<div className="card">
  <img className="card__img" src={btn_plus} alt="plus" />
  <p className="card__content">사진 추가하기</p>
  <input
    className="card__input"
    type="file"
    id="detail_image"
    accept="image/*"
    onChange={e => {
      createImagePreview(e);
    }}
    />
</div>

작동되는 Flow 는 3 -> 2 -> 1 순이다.
input 에서 변경되는 이벤트가 발생하는 경우에
e 를 createImagePreview 에 먼저 넘겨준 이후에,
이 함수에서 해당하는 Files 를 읽어온다.
reader 가 Onload 되면 setImageUrl 함수를 통해 결과값을 state 에 담는다!


3. 선택된 파일 읽기

먼저, 전송을 trigger 할 수 있는 버튼을 만들고, 버튼에 onClick 함수를 정의해 준다.
이미지 파일을 보내기 위해서는 FormData 객체에 append(key, value)
혹은 append(key, value, filename)으로 파일값을 추가하여 전송하면 된다.

files 뿐만 아니라 여러가지 key, value 쌍을 추가할 수 있으며,
전송 시, 헤더에 content-type을 multipart/form-data로 명시해주어야
서버에서 적절하게 파싱을 진행할 수 있다.

onClickHandler = event => {
    const formData = new FormData();
    formData.append(
      "uploadImages",
      imgfile
    );
    const config = {
      headers: {
        "content-type": "multipart/form-data"
      }
    };
    axios.post(`uploadAPI`, formData, config);
  };

<button onClick={this.onClickHandler}>저장하기</button>
profile
프론트 엔드와 심리학을 공부하는 대학생입니다 :)

0개의 댓글