본문 바로가기

React

[React] image 파일 압축해서 FormData형식으로 서버에 보내기

사용할 라이브러리 :

browser-image-compression

yarn add browser-image-compression


//설치후 사용할 컴포넌트에서 import해오기
import imageCompression from 'browser-image-compression';

 

 

먼저 이미지를 업로드 할 HTML 태그를 만든다. 나는 styled-components를 사용해서 만들었다. 

<UploadForm onSubmit={submit}> //form 태그 

       <Upload
        type="file"
        ref={fileInput}
        onChange={getImage}
        accept="image/*"/> //input태그

       <SubmitButton
        type="submit">
        게시하기
       </SubmitButton> //button 태그

</UploadForm>

 

 

버튼을 클릭했을 때, 파일을 가져온다. 이 때 주의해야 할 점은, 여타 다른 선택자로 파일을 가져와서는 안된다. onChange에서 event를 통해서 파일을 가져와야 한다는 사실을 잊지말자. 나는 이 부분 때문에 많은 시간을 허비했다...

    //이미지 가져오기
    const getImage = event => {
        const reader = new FileReader();
        const file = event.target.files[0]; //이벤트를 통해서 파일을 가져오기
        actionImgCompress(file) //이미지 압축 함수
    }

event.target.files[0]을 통해서 파일을 꺼낸다. 그 파일을 미리 만들어둔 actionImgCompress()에 넣어준다. 

 

 

const [compressedImage, setCompressedImage] = useState(null);


//이미지 압축하기 
    const actionImgCompress = async fileSrc => {
        console.log("압축 시작");

        //압축할 옵션 내용
        const options = {
          maxSizeMB: 0.2,
          maxWidthOrHeight: 1920,
          useWebWorker: true
        };

        try {
          //imageCompression함수의 첫번째 인자는 파일, 두번째 인자는 옵션
          const compressedFile = await imageCompression(fileSrc, options);
          setCompressedImage(compressedFile)
        } 
        catch (error) {
          console.log(error);
        }
    };

imageCompression라는 라이브러리의 함수를 사용해 이미지를 압축한다. 첫번째 인자는 가공할 대상, 두번째 인자는 가공할 내용물이다. setCompressedImage라는 미리 만들어둔 useState에 값을 넣는다. 이 compressedImage값은 formData에 넣을 것이다. 

 

 

    //이미지 보내기.
    const submit = async event => {
      event.preventDefault()
      await sendFormData(compressedImage)
    }


	//FormData로 변환하기 
    const sendFormData = async(image) => {
        const formData = new FormData();
        //formData에 압축 이미지 파일 저장.
        formData.append('image', image)
        
        await axios
        .post(`/books/9791160022988/reviews/images`, 
        formData , 
        {headers: {'Content-Type': 'multipart/form-data',}}
        )
    }

sendFormData 함수를 만들고, 그 함수에 아까 압축한 compressedImage파일을 넣는다. sendFormData함수 안에서 new FormData()를 통해서 인스턴스를 생성한다. 그 다음 formData.append라는 메서드를 사용해서, key값을 설정해주고, 파일을 넣는다. 그리고 파일이 저장된 이 formData를 axios의 데이터 내용물에 넣어준다. 여기서 주의할 점이 한 가지 더 있다면, 꼭 헤더의 content-type을 넣어주어야 한다. 이렇게 해서 데이터를 전송하면 성공!!

 

 

전체 코드 : 

//import 부분
import React, {useRef, useState} from "react";
import styled from "styled-components";
import imageCompression from 'browser-image-compression';
import instance from "../shared/Request";


const ReviewWrite = (props) => {
    const [compressedImage, setCompressedImage] = useState(null);

    //업로드 버튼 클릭하기 
    const selectImage = () => {
        fileInput?.current.click()
    }

    //이미지 가져오기
    const getImage = event => {
        const reader = new FileReader();
        const file = event.target.files[0];
        actionImgCompress(file)

        reader.readAsDataURL(file);
        reader.onloadend = () => {
            dispatch(uploadAcions.showPreview(true))
            dispatch(uploadAcions.setPreview(reader.result))
        }
    }

    //FormData로 변환하기 
    const sendFormData = async(image) => {
        const formData = new FormData();
        //formData에 압축 이미지 파일 저장.
        formData.append('image', image)
        
        const result = await instance
        .post(`/books/9791160022988/reviews/images`, 
        formData , 
        {headers: {'Content-Type': 'multipart/form-data',}}
        )
        return result.data
    }

    //이미지 보내기.
    const submit = async event => {
      event.preventDefault()

      const result = await sendFormData(compressedImage)
    }

    //이미지 압축하기 
    const actionImgCompress = async fileSrc => {
        console.log("압축 시작");

        //압축할 옵션 내용
        const options = {
          maxSizeMB: 0.2,
          maxWidthOrHeight: 1920,
          useWebWorker: true
        };

        try {
          //imageCompression함수의 첫번째 인자는 파일, 두번째 인자는 옵션
          const compressedFile = await imageCompression(fileSrc, options);
          setCompressedImage(compressedFile)
        } 
        catch (error) {
          console.log(error);
        }
    };



    return (
        <React.Fragment>

                    <UploadForm 
                        onSubmit={submit}>

                        <Upload
                        type="file"
                        ref={fileInput}
                        onChange={getImage}
                        accept="image/*"/>

                        <SubmitButton
                        type="submit">
                        게시하기
                        </SubmitButton>

                    </UploadForm>

        </React.Fragment>

    )
}

 

 

참고한 자료 : 

https://medium.com/@fabianopb/upload-files-with-node-and-react-to-aws-s3-in-3-steps-fdaa8581f2bd

 

Upload files with Express and React to AWS S3 in 3 steps

A dead simple way to upload your files to AWS S3 using Express and React, also using TypeScript.

medium.com

https://www.youtube.com/watch?v=NZElg91l_ms