1

I have a button that changes icon when you drag the button down via Touch Event. Event handling logic is bound to Button containing the Icon component. When this component gets changed the whole event handling gets stuck.

I thought that event would bubble through the icon and will work normally at the level of component actually handling the events, but sadly when icon is replaced this is stuck.

Expected behavior: When you drag down the button down the icons should change all the way from icon 1 to 3, when you release icon changes back to icon 1

export const DragButton: React.FC = () => {
  const buttonRef = useRef<HTMLDivElement>(null);
  const [state, setState] = useState<State>("Idle");
  const [icon, setIcon] = useState(<AccessAlarms />);
  const [mousePos, setMousePos] = useState<{ x: number; y: number }>({
    x: 0,
    y: 0
  });

  const onTouchStart = (e: React.TouchEvent) => {
    setState("Pressed");
  };

  const onTouchEnd = (event: React.TouchEvent) => {
    setState("Released");
    setIcon(<AccessAlarms />);
  };

  const onTouchMove = (event: React.TouchEvent) => {
    setMousePos({ x: event.touches[0].clientX, y: event.touches[0].clientY });
    if (state == "Pressed") {
      if (event.touches[0].clientY > 200) {
        setIcon(<Accessibility />);
      } else if (event.touches[0].clientY > 100) {
        setIcon(<ChangeHistory />);
      } else {
        setIcon(<AccessAlarms />);
      }
    }
  };

  return (
    <ButtonDiv
      ref={buttonRef}
      onTouchStart={(event) => onTouchStart(event)}
      onTouchEnd={(event) => onTouchEnd(event)}
      onTouchCancel={(event) => onTouchEnd(event)}
      onTouchMove={(event) => onTouchMove(event)}
    >
      <Button>{icon}</Button>
      {mousePos.y}
    </ButtonDiv>
  );
};

What can be causing this behavior? It seems that removal of element where event originated is the problem, how could this be solved?

Sandbox is here, it is needed to use either Touchscreen or switch to mobile view in dew tools https://codesandbox.io/s/draggable-button-58vw2?file=/src/DragButton.tsx

Jarek
  • 7,425
  • 15
  • 62
  • 89
  • 1
    What is the expected result? You drag down and then the value should change up/down depending on the dragging? Or should it just change the state on drag down? – AWolf Oct 12 '20 at 19:20
  • When you drag down icons should change all the way from icon 1 to 3, when you release icon changes back to icon 1 – Jarek Oct 12 '20 at 19:24
  • 1
    OK, I think I know what's going on here. You can find the demo [here](https://codesandbox.io/s/draggable-button-yrkx1?file=/src/App.tsx). It shouldn't lose the move event during dragging. I think it's happening because your component re-renders and then the event target will be lost. The trick with the event adding was mentioned [here](https://stackoverflow.com/questions/33298828/touch-move-event-dont-fire-after-touch-start-target-is-removed). – AWolf Oct 12 '20 at 20:52
  • 1
    Amazing! Thank you very much! – Jarek Oct 12 '20 at 21:14
  • 1
    I've changed this code a bit as I've heard from pointer-events and [setPointerCapture](https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture) on Twitter. Works better and it also supports mouse events. Logic slightly change but the idea of the dragging is still there - https://codesandbox.io/s/draggable-button-forked-n5gl3 – AWolf Dec 02 '20 at 20:23

0 Answers0