기존에 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 이벤트만 걸면 되겠지? 라는 생각을 하고있었는데
실제 framer motion의 타입 선언 부분을 찾아보니
dragControl은 PointerEvent
만을 지원하고, touch event를 지원하지 않았다.
따라서 touch event만을 추가해서 문제를 해결할 수 없었다...
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>
);
}