React-dnd: HTML5Backend stops dragging when there elements in the DOM that appears/disappear in the drag event: CHROME

Created on 1 Apr 2020  ·  3Comments  ·  Source: react-dnd/react-dnd

Describe the bug
We have a serious problem with the html5backend. We need to generate some gaps to guide the user where to drop the dragged element, we want those gaps to be only visible while the element is dragging.
In firefox works perfect but in chrome, the cards launch the stop dragging event inmediately after the start dragging event.

Reproduction
https://codesandbox.io/s/react-dnd-sortable-holes-bq2oe
Each card is draggable and when the user starts dragging orange gaps appears.
image

image

In firefox works like a charm, but in chrome the stop event is launched inmediately after the start event.

As you can see in the console :
image

  • OS: [e.g. iOS]
  • Browser: Bug in Chrome Versión 80.0.3987.162, works perfect in firefox 74.0 (64-bit)

Any help will be really appreciated, we really need this functionallity.

Most helpful comment

Our team have improved the state workaround creating a custom hook for the drag and drop provider, in any case that any of you face this problem, here is a solution while the bug is solved.

https://codesandbox.io/s/react-dnd-sortable-gaps-custom-9tl13

The main part consist on define a Context and a Provider to store the dragging status.

const DndContext = React.createContext([{}, () => {}]);

const DndCustomProvider = props => {
  const [state, setState] = useState({ dragging: false });

  return (
    <DndProvider backend={props.backend}>
      <DndContext.Provider value={[state, setState]}>
        {props.children}
      </DndContext.Provider>
    </DndProvider>
  );
};

Secondly, using setTimeout in drag begin function the end dispatched is avoided.

  const [context, setContext] = useContext(DndContext);

  const [collected, dragRef] = useDrag({
    ...,
    begin: monitor => {
      setTimeout(() => {
        setContext(() => ({ dragging: true }));
      }, 0);

      if (begin) {
        begin(monitor);
      }
    },
    end: (item, monitor) => {
      setContext(() => ({ dragging: false }));

      if (end) {
        end(item, monitor);
      }
    },
    ...
  });

  return [
    {
      ...collected,
      isDragging: context.dragging
    },
    dragRef
  ];

And finally, isDragging collected value is overwritten with the context value.

All 3 comments

I've found a workaround, reading a lot, for this issue, setting a timeout and a state variable that I pass through components, I don't like it very much, because in these simple cases its easy to do, but in complex cases I should use context or something similar to make everything work.
https://codesandbox.io/s/react-dnd-sortable-holes-vxeus

I hope that you can guide me through a better solution, I would like to use the isDragging from the library instead of this workaround.

Our team have improved the state workaround creating a custom hook for the drag and drop provider, in any case that any of you face this problem, here is a solution while the bug is solved.

https://codesandbox.io/s/react-dnd-sortable-gaps-custom-9tl13

The main part consist on define a Context and a Provider to store the dragging status.

const DndContext = React.createContext([{}, () => {}]);

const DndCustomProvider = props => {
  const [state, setState] = useState({ dragging: false });

  return (
    <DndProvider backend={props.backend}>
      <DndContext.Provider value={[state, setState]}>
        {props.children}
      </DndContext.Provider>
    </DndProvider>
  );
};

Secondly, using setTimeout in drag begin function the end dispatched is avoided.

  const [context, setContext] = useContext(DndContext);

  const [collected, dragRef] = useDrag({
    ...,
    begin: monitor => {
      setTimeout(() => {
        setContext(() => ({ dragging: true }));
      }, 0);

      if (begin) {
        begin(monitor);
      }
    },
    end: (item, monitor) => {
      setContext(() => ({ dragging: false }));

      if (end) {
        end(item, monitor);
      }
    },
    ...
  });

  return [
    {
      ...collected,
      isDragging: context.dragging
    },
    dragRef
  ];

And finally, isDragging collected value is overwritten with the context value.

Does anyone have a solution or an idea for a patch for this issue that doesn't involve such a workaround?

Was this page helpful?
0 / 5 - 0 ratings