drag event를 이용한 메뉴 등록 + 🐞

May·2023년 3월 29일
0
post-thumbnail

우리 집 생활비를 절약하기 위해 한 달 식단표를 만들 수 있는 개인 프로젝트를 진행중이다.


초기에 구현하려고 했던 기능.
옆 메뉴바에서 메뉴를 끌면 -> 달력의 각 칸에 메뉴가 들어가는 형식으로 진행하고 싶었다.

찾아보니 드래그 이벤트를 통해서 진행할 수 있다고 한다

메뉴 단어를 감싸는 태그에 draggable="true" 가 들어가야 했다. 그래야 드래그가 된다

달력 컴포넌트와 메뉴 컴포넌트가 나뉘어져 있었기 때문에 어떻게 하면 메뉴값을 달력 컴포넌트에 전달할 수 있을까 생각을 했는데,

  1. 메뉴 드래그가 시작되면 (메뉴의 onDragStart 이벤트) 전역 state에 선택한 메뉴를 할당해서
  2. 달력 칸에 도착하면(달력 칸에서의 onDrop 이벤트) 선택한 메뉴를 달력에 보여주는 것

생각보다 너무 너무너무너무 복잡했다.

일단 메인메뉴 한개만이라도 달력으로 옮겨보자.

드래그 이벤트를 처음 접해봐서 어떤 이벤트를 사용해야할지 고민을 많이했다.

onDr 만 쳐도 나오는 무수한 이벤트들...

어떤 이벤트가 어떻게 작동되는지부터 확인했다.

이용한 코드

...
<span
          draggable="true"
          onDragStart={() => {
            console.log("드래그가 시작할 때");
          }}
          onDragCapture={() => {
            console.log("드래그 하는 중");
          }}
        
          onDragEnd={() => {
            console.log("드래그가 끝날 때");
          }}
          key={index}
        >
          {sideMenu}
</span>
...

일단 ~ 하는 중일때의 이벤트는 최대한 사용하지 않으려고 했다.
드래그 중일때 이벤트를 사용하게 되면 너무... 낭비된다고 생각했다..

드래그를 하는 중에 무한히 증가하는 횟수

그렇게 해서 메뉴 드래그를 시작할 때 전역 state에 선택한 메뉴를 할당시켜주고,
달력에 드래그가 도착하고 누르고 있던 마우스를 뗄 때(달력 컴포넌트에서 drop 이벤트가 발생했을 때) 전역 state값을 보여주게끔 구현했다.

하지만 내가 원하는 건 드래그가 완료됐을 때 도착한 달력 칸에'만' 메뉴가 나왔으면 했다.

날짜로 구분을 해줘야 했는데, 날짜 데이터는 메뉴 드래그가 아닌 달력 날짜 칸에서 얻을 수 있었다.
날짜 칸을 직접 드래그 할 일은 없으니 drag 이벤트보단 onDropCapture 이벤트를 통해서 메뉴 드래그가 drop 되는 중에 날짜 데이터를 받을 수 있도록 했다.

find()를 이용해서 달력의 날짜와 드래그가 drop 됐을 때 날짜 데이터를 비교해서 날짜가 같은 것만 달력에 표시될 수 있도록 했다.

또, 다른 날짜에 메뉴를 드래그하게 되면 달력에 먼저 등록돼있던 메뉴들이 남아있어야 했다!
그래서 menuList(array)를 state로 만들어서 메뉴를 drop 할 때마다 계속 추가되도록 했다.

또...
이미 메뉴가 있던 달력칸에 다른 메뉴를 드래그하게 되면 새로 드래그 한 메뉴로 바뀌어야 했다....😤

drop 했을 때의 날짜와 // menuList에서의 날짜가 같은 객체가 있다면 그 객체를 수정하는 형식으로 진행했다.

menuList state 자체를 변경할 수 없기 때문에 그걸 복사해서
복사한 객체 요소를 새로 드래그 한 메뉴로 변경,
복사한 객체를 다시 setState 인자로 넣어서 state를 변경해줬다.

(...)
 
      let copyMenuList = [...menuList];

      copyMenuList.map((menu) => {
        if (menu === copyMenuList.find((menu) => menu.date === menuDate)) {
          mainMenu !== "" && (menu.mainMenu = mainMenu);
        }
      });

      setMenuList(copyMenuList); 

(...)

정말 뿌듯했다
내가 기획했던 기능 그대로 구현됐다.

그러나

나는 국거리와 반찬을 다같이 달력에 표시해야 했고

  • 국거리를 드래그했는데 다른 날짜에 드래그했던 메인메뉴와 같이 보여지고
  • 국거리를 수정하려고 했는데 기존에 등록되어있는 메인메뉴가 사라지고
  • 메뉴바에서 달력쪽으로 드래그 하지 않고 드래그 하는 척만 한 후 다른 분류의 메뉴를 드래그하면 함께 등록이 된다거나..

등등...
골치아픈 버그들이 많았다

국거리를 수정하려고 했는데 기존에 등록되어있는 메인메뉴가 사라지는 현상

복사한 menuList에 새로운 드래그 메뉴로 수정을 할 때의 문제였다.

기존코드

      copyMenuList.map((menu) => {
        if (menu === copyMenuList.find((menu) => menu.date === menuDate)) {
          menu.mainMenu = mainMenu;
          menu.soup = soup;
          menu.sideMenu = sideMenu;
        }
      });

mainMenu, soup, sideMenu에 새로 드래그한 메뉴를 할당해준다고 하자
메인메뉴와 국거리, 반찬 한번에 3개의 메뉴를 드래그 할 순 없다.
그렇기 때문에, 국거리만 바꾸려고 하면 저 상태에서는 mainMenu, sideMenu는 "" 빈 문자열 상태이다. (메뉴를 드래그 할 때부터 state가 변경되기 때문에 기본 상태가 됨)

그렇기 때문에, 등록된 국거리를 다른 국거리로 바꾸려고 하면

          menu.mainMenu = "";
          menu.soup = soup;
          menu.sideMenu = "";

이 상태로 menuList가 바뀌게 된다.
당연히 기존에 드래그 했던 메뉴들은 빈 문자열이 되고 우리 눈에는 보이지 않게 되는 것

그래서,

      let copyMenuList = [...menuList];

      copyMenuList.map((menu) => {
        if (menu === copyMenuList.find((menu) => menu.date === menuDate)) {
          mainMenu !== "" && (menu.mainMenu = mainMenu);
          soup !== "" && (menu.soup = soup);
          sideMenu !== "" && (menu.sideMenu = sideMenu);
        }
      });

      setMenuList(copyMenuList);

각 메뉴의 state가 빈 문자열이 아니라면, 바뀐 메뉴로 객체를 변경해주는 코드로 다시 작성해줬다.

메뉴바에서 달력쪽으로 드래그 하지 않고 드래그 하는 척만 한 후 다른 분류의 메뉴를 드래그하면 함께 등록이 되는 현상

사진과 같이 반찬을 달력에 드래그 하지 않았는데도 국거리를 등록할 때 반찬이 같이 등록됐다.

메뉴 드래그를 시작할 때 전역 state에 해당 메뉴가 할당되는 프로세스이다.
그러므로, 달력에 드래그 하지 않았어도 메뉴 드래그가 시작됐기 때문에 전역 반찬 state에는 시금치무침이 등록된다.
(달력에 드래그 했을 때는 전역 state 초기화를 하는 코드가 작성되어 있지만 해당 상황에서는 달력 근처에도 메뉴가 드래그되지 않았기 때문에 성사되지 않는다... ㅠ)

반찬 state에 시금치무침이 등록되어있는 상태에서 국거리를 등록하니, 반찬과 국거리가 같이 등록되는 것이다..

이런 상황을 대비하기 위해
메뉴 드래그가 끝났을 때에도 전역 state를 초기화 해주는 코드를 추가해주었다.

onDragStart={() => setSideMenu(sideMenu)}

// 메뉴바에서 달력으로 드래그 하지 않았을 때 초기화
onDragEnd={() => setSideMenu("")}

얼추 주요 기능이 완성된 느낌이다! 기능을 이것저것 넣을 계획이다 빠르게 내 머리가 잘 돌아갔으면 😇

profile
ฅ˘◡˘ฅ

0개의 댓글