DND를 위해 touch event 비활성화 하기

sumi-0011·2023년 6월 29일
0
post-thumbnail

문제 상황

기존에 framer motion의 Reorder 컴포넌트를 이용해서 DND를 구현하고, 동작되는 것을 확인해보았었다.
그런데 어느 순간 개발 모드에서 동작하지 않는 것을 발견하였다.

우리는 스토리북 또한 쓰고 있어서 스토리북을 확인해 보았는데 스토리북에서는 정상적으로 동작했다.
그럼 뭐가 문제지..?

문제 발견

내가 크롬 환경에서 mobile 화면으로 테스트하기 위해
모바일 모드로 개발을 하고있었다.
모바일 모드일 때는 PC에만 있는 pointer 이벤트가 없어지고, touch 이벤트만 동작한다는 것을 간과했던 것이다.

실제로 PC화면을 확인해보니 정상적으로 돌아가고 있었다.

스토리북 환경에서 정상적으로 DND가 돌아갔던 것은
스토리북은 PC 모드로 돌아가기 때문이였던 것이다.

그러면 touch event에도 이벤트를 걸면 쉽게 해결할 수 있지 않을까?

기존 코드를 확인해보자

기존 코드를 확인해 보면,
MenuIcon 컴포넌트를 이용해서 드래그를 커스텀해서 동작시키고 있다.
onPointerDown 이벤트에 드래그를 시작 이벤트를 걸어, 드래그를 컨트롤 하고 있는데
이때 touch 이벤트를 간과한 것이 문제라고 생각하였다.

function QuestionWithDnd({ item }: Props) {
  const dragControls = useDragControls();

  return (
    <Reorder.Item
      as="div"
      data-testid="dnd-item-component"
      value={item}
      dragListener={false}
      dragControls={dragControls}
    >
      <Question item={item} rightElement={<MenuIcon onPointerDown={(e) => dragControls.start(e)} />} />
    </Reorder.Item>
  );
}

그러면 touch 이벤트만 걸면 되겠지? 라는 생각을 하고있었는데

dragControl은 PointerEvent만 지원한다.

실제 framer motion의 타입 선언 부분을 찾아보니
dragControl은 PointerEvent 만을 지원하고, touch event를 지원하지 않았다.
따라서 touch event만을 추가해서 문제를 해결할 수 없었다...

touchAction 비활성화 시키기

framer motion 공식문서에서 문제 해결을 위한 키를 찾을 수 있었다.

스타일을 이용해 touchAction을 비활성화 시키면, 강제로 pointer 이벤트가 실행되는 것이다!

참고

문제 해결 하기

function QuestionWithDnd({ item }: Props) {
  const dragControls = useDragControls();

  return (
    <Reorder.Item
      as="div"
      data-testid="dnd-item-component"
      value={item}
      dragListener={false}
      dragControls={dragControls}
    >
      <Question
        item={item}
        rightElement={
          <MenuIcon 
            onPointerDown={(e) => dragControls.start(e)} 
            style={{ touchAction: 'none' }}  // style을 추가해줌으로써 해결할 수 있었다. 
            />
        }
      />
    </Reorder.Item>
  );
}
profile
안녕하세요 😚

0개의 댓글