사이드 프로젝트 개발 과정 - (옷 태깅 기능 구현, react-draggable)

knh6269·2024년 6월 14일
1

ootd.zip

목록 보기
11/16
post-thumbnail

도입

카카오톡, 인스타그램등에는 사진위에 스티커, 이미지 등을 태그할 수 있는 기능이 있다. ootdzipootd에 내 옷을 태그할 수 있다. 오늘은 react-draggable을 활용해 옷 태깅 기능을 구현해보겠다.


요구 사항

디자인

기능

  • 유저는 사진을 클릭해 태그 등록 모달창을 연다.
  • 유저는 검색어나, 필터를 활용해 내 옷장에 있는 옷을 찾아 등록한다.
  • 유저는 원하는 위치로 옷 태그를 옮길 수 있다.
  • 유저는 원하지 않는 태그를 x 버튼을 클릭해 지울 수 있다.

옷 태그 구현

태그 요소

clothesId: number; //옷 id
clothesImage: string; //옷 이미지 주소
coordinate : { xrate: string; yrate: string; } //태그 좌표 위치
deviceSize: { deviceWidth: number; deviceHeight: number }; //등록한 유저의 유대폰 크기
name: string; //옷 이름
brand: string; //옷 브랜드

⚠ 오류 발생. deviceSize를 저장하게 된 이유

react-draggable의 위치는 (0,0)을 기준으로 (xrate, yrate)만큼 이동해 정해지는데 등록한 태그의 위치가
다른 유저의 휴대폰에서는 다른 경우가 발생했다. 유저끼리의 휴대폰 크기가 다르기 때문에 생긴 현상이다.
그래서 나는 옷을 등록하는 유저의 휴대폰 크기를 저장해 태그를 보는 유저와의 휴대폰 크기 차이만큼 수정해주기로 했다.


옷 태그 버튼 클릭

상태값 변화를 위한 복사

const newTag = JSON.parse(JSON.stringify(imageAndTag));

기존 옷 태그 리스트가 존재하는 경우 ⭕

옷 리스트의 마지막 인덱스로 push 해준다.

newTag[slideIndex].ootdImageClothesList?.push({
  clothesId: searchResult![index].id,
  clothesImage: searchResult![index].imageUrl,
  brand: searchResult![index].brand.name,
  name: searchResult![index].name,
  coordinate: {
    xrate: '0',
    yrate: '0',
  },
  deviceSize: {
    deviceHeight: componentHeight,
    deviceWidth: componentWidth,
  }});

기존 옷 태그 리스트가 존재하지 않는 경우 ❌

옷 리스트를 새로운 객체 배열로 만들어준다.

newTag[slideIndex].ootdImageClothesList = [
  {
    clothesId: searchResult![index].id,
    clothesImage: searchResult![index].imageUrl,
    brand: searchResult![index].brand.name,
    name: searchResult![index].name,
    coordinate: {
      xrate: '0',
      yrate: '0',
    },
    deviceSize: {
      deviceHeight: componentHeight,
      deviceWidth: componentWidth,
    }},
]; 

옷 태그 위치 수정

<Draggable
  key={index}
  bounds=".image"
  onDrag={(e, data) => onDrag(index, ootdIndex, e, data)}
  onStop={handleStopDrag}
  position={{
    x: Number(element.coordinate.xrate),
    y: Number(element.coordinate.yrate),
  }}
  >
  <div className="sample">
    <TagInformation
      clothId={element.clothesId}
      clothImage={element.clothesImage}
      caption={element.caption}
      brand={element.brand}
      clothSize={element.size}
      category={element.category}
      name={element.name}
      state={element.state as 'dark' | 'light'}
      onTouchEnd={() =>	onClickCloseButton(ootdIndex, index)}
      />
  </div>
</Draggable>

⚠ 오류 발생. defaultPosition을 사용하니 생기는 오류

기존에 나는 Draggable 요소의 초기 좌표를 설정하는 defaultPosition을 사용했다. 태그를 등록할때는 문제가 없었지만 태그를 삭제했을때 해당 인덱스의 태그가 삭제되는게 아니라 마지막 인덱스의 태그가 삭제되는 현상이 발생했다. 이유를 찾고자 디버깅을 해보았는데 분명 삭제는 잘 되지만 렌더링이 되지 않는 문제가 있었다. 그래서 나는 defaultPosition 이 아닌 상태가 변했을 때 바로 반영이 되는 position을 활용해보아야겠다 라고 생각했고 정상 작동하였다!

⚠ 오류 발생. 옷 삭제 버튼이 클릭되지 않는 오류

Draggable로 감싸져있어서 인지 클릭 이벤트가 드래그 이벤트로 인식되어 정상 작동하지 않았다. 이에 나는 드래그 이벤트와 클릭 이벤트를 구분하기 위해 isDragging 상태를 만들었다.
onDragisDraggingtrue로 업데이트 하고, onStopisDraggingfalse로 업데이트 한 뒤,
onClick 이벤트에 if(isDragging) return ; 코드를 추가해 구분해주었다. 이렇게 하니 정상 작동하였다!


완성 화면


정리

유저들이 원하는 위치에 자기 옷을 태그하는 기능은 이 아이디어를 처음 생각했을 때 부터 생각했던 기능인데 드디어 만들어보니 기분이 좋다 :) 하지만 라이브러리를 이용해서 그런지 태그가 빠르게 다른위치로 가지는 못한다. 다음 리팩토링 때 좀 더 공부하고 수정해보아야겠다.

0개의 댓글