react, js 이미지 업로드/ 미리보기/ 삭제하기

SC Ryu·2023년 7월 7일
0
post-thumbnail

0. 목표

react에서 이미지 업로드, 미리보기, 삭제하기를 제작하려고 한다.
(function방식으로 제작 react hook을 활용하여 제작한다.)

  1. 사진을 업로드한다
  2. 업로드된 사진을 배열로 저장한다
  3. 업로드한 사진을 미리보기 형식으로 styling
  4. 업로드된 사진 hover시 삭제 가능하게 설정한다

1. 배열 저장하기

새롭게 추가할 사진 배열 설정

const [imageItems, setImageItems] = React.useState([]);

useState를 이용해 imageItems라는 배열을 설정한다

배열에 첨부될 object는

{ id: 파일이름, file: 사진파일, url: 사진파일 url }

형식이 될것이다

사진을 불러들일수있는 input 태그를 설정한다

<input 
 type={'file'}
 accept={'image/*'}
 ref={photoInput}
 onChange={handleAddImageFile}
 style={{ display: 'none' }}
/>

위 input 에서 체크 해야할 사항은

  1. input style을 'none'처리
  2. ref={photoInput}

따로 버튼을 두어 useRef를 활용하여 ref로 클릭을 연결해주기 위함이다.

handleAddImageFile 함수를 만들어보자

const handleAddImageFile = (e) => {
    e.preventDefault()
    let reader = new FileReader()
    let file = e.target.files ? e.target.files[0] : null
    if (!file) {
      return
    }
 reader.onloadend = () => {
      setImageItems([
        ...imageItems,
        { id: file.name, file: file, imagePreviewUrl: reader.result },
      ])
    }
    reader.readAsDataURL(file)
  }

handleAddImageFile 는 이미지를 load하고 파일불러오기에서 파일을 선택시 imageItems에 넣어주는 역활을 한다.

2.버튼에 input 기능 구현하기

useRef를 활용하여 photoInput를 등록해주고 input내부의 ref에 담아준다

const photoInput = useRef()

  const handleAddPhotoClick = () => {
    photoInput.current.click()
  }

이후 버튼에 onClick 이벤트로 handleAddPhotoClick를 넣어주면 된다

useRef를 활용한 current.click()함수로 인해 버튼에 input기능을 실행할수있게 가능하다

<button
 onClick={() => handleAddPhotoClick()}
>
 <closeIcon/>
   이미지 추가하기
</button>

이제 추가된 배열을 매핑한다.

3. 배열 매핑하기

<div direction="row">
 {imageItems.map((item, index) => {
  return (
   <ImageBox
    key={index}
    // absolute 대상 선택을위해 relative 설정
    style={{ position: 'relative' }}
    //클릭시 삭제 처리
    onClick={() => contentRemoveImage(item.imagePreviewUrl)}
   >
    <img src={item.imagePreviewUrl} />
	<div className="bg_hover" />   //마우스 hover시 삭제style 제작
 	<div className="bg_hover_text">삭제</div> //마우스 hover시 삭제style 제작
   </ImageBox>
  )
 })}
</div>

map 을 이용해 배열 imageItems을 활용해 item 내부의 인자값들을 활용해서 image요소들에 각요소들에 넣어준다

매핑후 필자는 style-component를 사용하여 내용을 지정하여 style처리를 해주었다.

매핑 스타일은 아래와 같다

const ImageBox = styled.div`
  width: 60px;
  height: 60px;
  overflow: hidden;
  background-color: rgba(150, 150, 180, 0.3);
  margin: 2px;
  border-radius: 4px;
  cursor: pointer;
  box-sizing: border-box;
  & .bg_hover {
    background-color: rgba(0, 0, 0, 0.48);
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    transition: ease-in-out 0.2s;
    opacity: 0;
    border: 3px solid rgb(100, 100, 100);
  }

  & > div.bg_hover_text {
    opacity: 0;
    color: #fff;
    padding: 8px;
    position: absolute;
    top: 50%;
    right: 50%;
    transform: translate(50%, -50%);
    transition: ease-in-out 0.2s;
  }

  &:hover .bg_hover,
  &:hover div.bg_hover_text {
    opacity: 1;
  }

  & > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: ease-in-out 0.25s;
  }

  &:hover > img {
    transform: scale(1.15);
    opacity: 0.8;
  }
`

4. 삭제하기 구현하기

const contentRemoveImage = (deleteUrl: any) => {
    setImageItems(imageItems.filter(item => item.imagePreviewUrl !== deleteUrl))
  }

contentRemoveImage함수를 만들어 준다

배열 imageItems 내부를 탐색 filter()를 이용해 선택한 대상과 같지 않은 url을 남겨준다.

contentRemoveImage 함수는 삭제하길 원하는 대상의 위치에 onClick이벤트로 넣어주면 된다

{imageItems.map((item, index) => {
  return (
   <ImageBox
    key={index}
    // absolute 대상 선택을위해 relative 설정
    style={{ position: 'relative' }}
    //클릭시 삭제 처리
    onClick={() => contentRemoveImage(item.imagePreviewUrl)}
   >
    <img src={item.imagePreviewUrl} />
	<div className="bg_hover" />   //마우스 hover시 삭제style 제작
 	<div className="bg_hover_text">삭제</div> //마우스 hover시 삭제style 제작
   </ImageBox>
  )
 })}

이렇게 하면 contentRemoveImage 내부의 인자값으로 받아온 item.imagePreviewUrl을 활용하여 대상을 제거 할수있다

추가1.

handleAddImageFile함수 내부에서 업로드하는 file에 접근이 가능하기 때문에
이를 활용하여

    if (file.size > 3024) {
      alert('파일 사이즈가 너무 큽니다.')
      return
    }

등 file크기제한, 이미지크기조절등 다양하게 활용할수 있다.

추가2

이미지 파일을 배열 imageItems에 모아놓은 상태이기에 이를 활용하여 업로드, 전송등 이 가능하다

profile
interactive Developer

0개의 댓글