본문 바로가기
trouble shooting

React 다중 이미지 업로드 훅

by dev정리 2022. 11. 2.

리액트 이미지 업로드 or 리액트 이미지 다중 업로드를 검색 하면 글이 많이 나오는데

소스가 모두 제각각이고 설명이 이해하기 힘들어서 여기저기서 소스를 짜집기해서 기능을 구현하고

다음 프로젝트에서 사용하기위해 훅으로 뺐다.

 

browser-image-compression 설치
npm i browser-image-compression

 

 

browser-image-compression

Compress images in the browser. Latest version: 2.0.0, last published: 7 months ago. Start using browser-image-compression in your project by running `npm i browser-image-compression`. There are 95 other projects in the npm registry using browser-image-com

www.npmjs.com

이미지 파일을 압축할때 사용할 라이브러리 입니다.

 

해당 훅을 사용하려면 browser-image-compression을 다운 받아야합니다.

 

import { useState } from "react";
//이미지 압축 라이브러리
import imageCompression from "browser-image-compression";

//limitCount 파일갯수제한
//isComp 압축 여부 true :이미지 압축 , false:이미지 압축안함
//imgMaxSize 압축 최대 크기 기본값1mb
//imgMaxWidthHeight 압축 이미지 최대 width,height 기본값1920px
const useImgUpload = (limitCount = 0, isComp = false, imgMaxSize = 1, imgMaxWidthHeight = 1920) => {
    //이미지 파일 & 프리뷰URL useState
    const [imgFiles, setImgFiles] = useState([]);
    const [imgUrls, setImgUrls] = useState([]);


    //이미지 가져오기 핸들러
    const handler = (e) => {
        //파일 가져오기
        const files = e.currentTarget.files;

        //state 초기화
        setImgFiles([]);
        setImgUrls([]);

        //파일 갯수 제한
        if (limitCount > 0) {
            if ([...files].length > limitCount) {
                alert(`이미지는 최대 ${limitCount}개까지 업로드가 가능합니다.`);
                return;
            }
        }


        //선택한 이미지 파일 반복문 돌리기
        [...files].forEach(file => {
            //이미지 파일만 올릴수 있게 체크
            if (!file.type.match("image/.*")) {
                alert('이미지 파일만 업로드가 가능합니다.');
                return;
            }

            //압축 옵션
            const options = {
                maxSizeMB: imgMaxSize,
                maxWidthOrHeight: imgMaxWidthHeight,
                useWebWorker: true,
            };


            if (isComp) {
                //이미지 압축
                imageCompression(file, options)
                    .then((res) => {
                        //압축 이미지 파일 담기
                        //blob to file blob을 file로 형변환
                        setImgFiles(imgs => [...imgs, new File([res], res.name, { type: "image/" + res.name.split(".")[1] })]);

                        //압축 이미지 url 담기
                        const reader = new FileReader(); // FileReader API로 이미지 인식
                        reader.onload = () => {// 사진 올리고 나서 처리하는 event
                            setImgUrls(imgUrls => [...imgUrls, reader.result]);
                        };
                        reader.readAsDataURL(res); //reader에게 file을 먼저 읽힘
                    })
                    .catch((error) => {
                        console.log("파일 압축 실패", error);
                    })
            } else {
                //이미지 파일 담기
                setImgFiles(imgs => [...imgs, file]);
                //압축 이미지 url 담기
                const reader = new FileReader(); // FileReader API로 이미지 인식
                reader.onload = () => {// 사진 올리고 나서 처리하는 event
                    setImgUrls(imgUrls => [...imgUrls, reader.result]);
                };
                reader.readAsDataURL(file); //reader에게 file을 먼저 읽힘
            }

        });

    }
    return [imgFiles, imgUrls, handler];
};

export default useImgUpload;
useImgUpload라는 이름으로 훅을 만들었다.
 
 
 
사용법
import useImgUpload from ".../hooks/useImgUpload";

const [files, fileUrls, uploadHandle] = useImgUpload(5, true, 0.3, 1000);

<input
    type="file"
    accept="image/*"
    multiple
    onChange={uploadHandle}
/>

 

  1. 훅을 임포트 한다.
  2. 어떤 형태로 저장 할지 매개변수로 옵션을 설정하고 변수명을 짓는다.
    • 매개변수1 ( 파일갯수 default=0 )
    • 매개변수2 (압축 여부 default=false )
    • 매개변수3 (압축 크기 default=1(mb) )
    • 매개변수4 (최대 이미지 크기 default=1000(px) )
  3. file타입의 input태그에 onChange 함수에 선언했던 핸들러를 쓴다.

이렇게 사용하면 input태그를 클릭하여 이미지 파일을 선택하면

files에는 실제 파일이 담기고

fileUrls에는 이미지의 프리뷰가 담긴다.