[경운마켓] 업로드 페이지 aws s3를 이용한 이미지 저장

해준박·2023년 10월 17일
0

프로젝트

목록 보기
1/6

주요기능

  1. 상품이미지 여러개 등록하기
  2. 이미지 클릭시 모달 창
  3. 이미지 업로드시 aws s3 저장
  4. form이 만족되지 않았을 경우 focus

1. 상품이미지 여러개 등록

<S.UploadImgInput
            onChange={onChangeImgInput}
            ref={uploadImgInput}
            type="file"
            accept="image/jpg, image/jpeg, image/png"
            multiple
          />

먼저, type=file인 input을 만들고, display:none 설정
useRef로 업로드버튼 클릭시 input으로 작동할 수 있도록 만들었다.

이미지 여러개 등록 후 미리보기

const onChangeImgInput = async (e: any) => {
    e.preventDefault();
    const files = e.target.files;
    const newFileList: string[] = [];

    if (files.length > 3) {
      alert("사진은 최대 3개까지 첨부할 수 있습니다");
      return;
    }

    for (let i = 0; i < files.length; i++) {
      const resizedImage = await resizeImage(files[i]);
      newFileList.push(resizedImage as any);
    }

    setFileList([...fileList, ...newFileList]);
  };

현재 filelist에 이미지 파일이 저장된다.
1. files에 업로드한 이미지를 저장
2. 3개가 넘을경우 alert
3. for문을 이용하여 이미지 리사이징
4. setFileList([...fileList, ...newFileList]) 이렇게 한 이유는 기존 fileList에 추가로 또 업로드 될 경우도 있으니 위와 같이 코드를 짰다.


2. 이미지 클릭시 모달창

react-modal을 사용해서 구현

// Upload.tsx

const onClickModalOpen = (idx: number) => {
    setOnModal((prev) => !prev);
    setSelectImg(URL.createObjectURL(fileList[idx] as any));
    document.body.style.overflow = "hidden";
  };

  // 모달닫기
  const closeModal = () => {
    setOnModal(false);
    document.body.style.overflow = "auto";
  };

...

// 맨 밑부분에 추가
<Modal isOpen={onModal} onRequestClose={closeModal} selectImg={selectImg} />

Modal컴포넌트를 따로 만들어서 prop을 넘기는 식으로 진행했다

  • isOpen 과 onRequestClose 을 이용하여 현재 모달을 열고 닫을 수 있게 boolean형으로 state를 두었다
  • selectImg로 현재 클릭한 이미지도 넘길 수 있게 해줬다. 이미지가 blob형태라
  • URL.createObjectURL() 추가해야 문제없이 이미지를 볼수있었음..
  • overflow설정은 스크롤을 방지하려고 추가했던거같다
// Modal.tsx
const Modal = ({ isOpen, onRequestClose, selectImg }: any) => {
  return ReactDOM.createPortal(
    <ReactModal
      isOpen={isOpen}
      onRequestClose={onRequestClose}
      style={{
        overlay: {
          position: "fixed",
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          backgroundColor: "black",
          zIndex: "999",
          overflow: "hidden",
        },
        content: {
          display: "flex",
          flexDirection: "column",
          justifyContent: "center",
          alignItems: "center",
          background: "black",
          borderRadius: "4px",
          border: "none",
          overflow: "hidden",
          padding: 0,
        },
      }}
      shouldCloseOnOverlayClick={true}>
      <S.Button>
        <TiDelete onClick={onRequestClose} color="#fff" size={40} />
      </S.Button>
      <S.ImgWrap>
        <img src={selectImg} alt="사진" />
      </S.ImgWrap>
    </ReactModal>,
    document.body // 모달을 document의 body 아래에 렌더링
  );
};

ReactDOM.createPortal을 이용해서 documet.body를 추가했다 이렇게 해야 모달이 젤 위로 와서 성공적으로? 모달을 보여줄 수 있게된다

modal을 할때는 레이아웃 부분이 굉장히 까다로웠따..


3.이미지 업로드시 aws s3 저장


// submit했을 시
...
	const upload = fileList.map((file, idx) => {
      const params = {
        Bucket: "ikw-market",
        Key: `${Date.now()}.${idx}.webp`,
        Body: file,
      };
      return new AWS.S3().upload(params).promise(); 
    });

    // 비동기로 upload 함수 실행 후 aws s3 이미지 링크 저장
    const uploadResults = await Promise.all(upload);
    const imageUrls = uploadResults.map((result) => result.Location);
...

submit과 동시에 aws s3에 저장한다. map을 이용해서 현재 파일리스트의 모든 이미지를 업로드 하고

Bucket - aws s3에서 사용하는 버킷명
Key - 저장할 파일이름 + 확장자도 붙일수있었음
Body - 저장할 파일 종류


4. form이 만족되지 않았을 경우 focus

원래는 기본적으로 제공되어지는 input을 사용했다 근데 여기서는 단점이 여럿존재한다.

예를들어 maxlength, minlength 같은것들을 설정했을때 개발자도구를 열어 dom 속성에서 지워서 사용가능하다는 나름 치명?적인 단점이있음

이를 보안하려고 useForm을 사용하였다.

const { register, handleSubmit, setValue } = useForm<IForm>();

...

<S.UploadInput
            {...register("name", { required: true, minLength: 5, maxLength: 15 })}
            placeholder="최소 5글자"
          />

register("name")로 첫번째로 오는 인자는 input의 name이다. 글고 두번재로 오는 인자들은 추가로 설정 할 수 있는 속성들이 있음

setValue("name",function)으로 input의 value를 조절할수있음


개선 사항

  • placeholder로 명확한 설명이 필요할것같다.
  • 상품설명에도 최대 글자가 필요할 듯
  • 거래위치도 살짞애매하다
profile
기록하기

0개의 댓글