react-dnd: Cannot drag element twice. Uncaught Invariant Violation: Cannot call beginDrag while dragging.

os OS X El Capitan Version 10.11.4 (15E65) browser Google Chrome Version 51.0.2704.36 beta (64-bit) react-dnd 2.1.4 react-dnd-html5-backend 2.1.2

Error happens after a drag and drop where the source element has been removed after the drop when trying to drag the element again.

capture d écran 2016-05-05 a 14 18 14

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 8
  • Comments: 23 (2 by maintainers)

Most upvoted comments

On the off chance it’s helpful to anyone with this issue, I ran into this error message recently and it turned out to be because I was generating my components from a map command, and I was assigning them randomly-generated keys. When the list re-ordered, the keys would be re-generated randomly, so React DnD was losing connection to the components.

I changed my map commands to use deterministic keys that would stick with the component even after re-ordering, and the issue went away instantly. Obvious in hindsight, but frustrating until then!

Had the same problem here. Having a list of draggable and droppable items, and user can drag items to reorder.

Thanks @deepsweet for pointing out the issue. I used index as the key of the list items which would cause the re-mount of list items when order changes. Using unique identities as the key fixed the problem.

@vegetableman, i had the same issue and fixed it with @MatthewDavidCampbell solution here’s the old dropTarget

const dropTarget = { 
  canDrop (props) {
    return true
  },

  drop (target, monitor) {
    someFluxAction(target)
  }
}

to fix it, i’m returning an identifier to be read by endDrag and moved someFluxAction(target) to inside endDrag

const dropTarget = { 
  canDrop (props) {
    return true
  },

  drop (target, monitor) {
    return target.id
  }
}

const dragSource = {
  beginDrag(props) {
    return props
  },

  endDrag: function (props, monitor, component) {
    if (!monitor.didDrop()) {
      return;
    }
    var dropResult = monitor.getDropResult();
    someFluxAction(dropResult)
  }
}

hope that helps. -n

@gabrielbull Assuming you might be doing the same thing I was. Namely, you have some list and the items are wrapped as both DropTarget and DragSource. I was getting the same error. From the target specification, the drop function called a swap action but then it was if the element was from then on always monitored as dragable.

So I added an endDrag function to the source specification and consoled out when it got called. Never was the result. So the monitor never is made aware that dragging has finished. Likely, a tick cycle problem since the issue disappears then debugging with break points.

Rather than trying to understand the logic in the HTML5 Backend code, I changed the drop (or hover if that is where you make swaps) to return an identifier of the item being dropped on to. The return value can be captured by the endDrag (monitor.getDropResult()) and the swap executed from endDrag.

This solved my problem but I would love for somebody else to weight in on the original problem.

I have figured it out (at least for my specific case): I just improperly created completely new DropTarget(...)(DragSource(...)(MySortableItem)) instances every time inside a map() while rendering MySortableList. So after every order state change MySortableItems were unmounted and that’s why react-dnd was unable to fire END_DRAG event – original DOM nodes were detached and replaced.

Just check your items with componentWillUnmount.

For any future readers; I also sat staring blankly at my code wondering what was going wrong until I realised that even though my Sortable (i.e. Card) components were configured correctly, the problem lay with the fact that the components were being instantiated in the parent’s render method. This meant that whenever the parent component re-renderered, react-dnd would lose the connection to the child Sortable components.

@deepsweet

I have figured it out (at least for my specific case): I just improperly created completely new DropTarget(…)(DragSource(…)(MySortableItem)) instances every time inside a map() while rendering MySortableList. So after every order state change MySortableItems were unmounted and that’s why react-dnd was unable to fire END_DRAG event – original DOM nodes were detached and replaced.

Just check your items with componentWillUnmount.

Could you post a code snippet or is there working example?

Just wanted to add my experience for any future travelers.

I had a component that contained a <Droppable /> that would be conditionally rendered (separate from the rest of the droppables) once dragging started. I had to change this behavior to hide the component rather than unmounting it, otherwise when dragging stopped the error OP mentioned would show up.

Hope that helps someone!