react-dnd / dnd-core

Drag and drop sans the GUI [Legacy Repo]

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`isOver` and `DropTarget` `hover` race condition

deoxxa opened this issue · comments

I ran into an interesting bug today while I was writing some tests for a hover handler. The relevant code is here.

During a drag operation, for any drop target that the drag operation goes through, for the first frame of that hover incident, isOver will incorrectly return false in the hover handler. This is because that handler is called before the drop target is registered as being hovered over in the monitor's store.

I have a hover handler that looks like this:

  hover(props, monitor, _component) {
    if (!monitor.isOver({ shallow: true })) {
      return undefined;
    }

    do_the_thing();
  }

In normal use this probably doesn't matter, as you'd be hovering for more than one frame. In tests, however, it's easy to trigger. With the following test code, the do_the_thing() part never happens.

    backend.simulateBeginDrag([ dragSources.get(0).getHandlerId() ]);
    backend.simulateHover([ dropTargets.get(1).getHandlerId() ], { clientOffset: { x: 50, y: 35 } });
    backend.simulateDrop();
    backend.simulateEndDrag();

What I've done for now to work around this is call simulateHover twice. What this does is triggers two calls to hover - one where the drop target is not yet registered, and one where it is.

    backend.simulateBeginDrag([ dragSources.get(0).getHandlerId() ]);
    backend.simulateHover([ dropTargets.get(1).getHandlerId() ]);
    backend.simulateHover([ dropTargets.get(1).getHandlerId() ], { clientOffset: { x: 50, y: 35 } });
    backend.simulateDrop();
    backend.simulateEndDrag();

What a fun bug!