useDrag with dropEffect can break dragging capability
See original GitHub issueDescribe the bug
When using useDrag
with specified dropEffect
and props (deps array of the useDrag
), and deps have changed - it won’t allow to drag anymore after the first drop. Dragging is simply not working for some reason. Removing dropEffect
fixes the issue, so seems like it’s a bug.
Reproduction
Live Reproduction
Steps to reproduce the behavior:
- Take any example with hooks
- Add simple state in Container.jsx file, for example, counter:
import { useState } from react;
// ...
// ... in component code
const [counter, setCounter] = useState(0);
// ...
- Pass both
counter
andsetCounter
to SourceBox component - In
useDrag
hook, specify:
// ...
const [collected, drag] = useDrag(() => {
type: ItemTypes.BOX,
options: { dropEffect: 'copy' },
end: () => { setCounter(c => c + 1); },
// ... rest of the spec code
}, [counter]);
// ...
5. Drag once and drop
6. Verify dragging is not working anymore
**Expected behavior**
The case described above described should not break the dragging behavior.
**Screenshots**
N/A
**Desktop (please complete the following information):**
- OS: macOS
- Browser: Chrome
- Version 96.0.4664.55 (Official Build) (arm64)
**Additional context**
I didn't check if the same bug happens with Decorators, so don't know if it's just a Hooks-specific bug.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:5
- Comments:8
Top Results From Across the Web
Developers - useDrag with dropEffect can break dragging capability -
When using useDrag with specified dropEffect and props (deps array of the useDrag ), and deps have changed - it won't allow to...
Read more >Mastering Drag & Drop with ReactJS | by Shay Keinan
The Draggable component. We are going to create a class component that will give us the ability to wrap other components and make...
Read more >An Essential Guide to JavaScript Drag and Drop By Examples
This tutorial introduces you to the JavaScript Drag and Drop API and shows you how to handle drag and ... By default, only...
Read more >How to implement drag and drop in React with React DnD
What is react-dropzone? Display an image preview; Reorder images with drag and drop; React drag and drop libraries; react-beautiful-dnd. react ...
Read more >HTML5 Drag and Drop - James Priest CV - GitHub Pages
Prior to HTML5, the ability to use drag and drop operations was possible only ... The data is retrieved, split into an array,...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
After investigation, the root cause of the issue is that dependencies when changed issue a disconnect of the drag connector, but the reconnect is not fired.
Looking at the file useDrag
The
deps
paramater when changed causes new instances ofspec.options
andspec.previewOptions
to be created. These are passed to theuseDragSourceConnector
hook, which does the following:Whenever the
dragSourceOptions
input has a new reference, the hook is re-fired, which means theconnector.disconnectDragSource()
is called when thedragSourceOptions
are changed. That causes the connector to cleanup the old connection by disconnecting it. So far so good. Since the hook is re-fired, after the cleanup, theconnector.reconnect()
should be fired to re-connect the connector with the source.However, the problem lies here:
The re-connection will only happen if the
didChange
variable is true. In the case of the same drag element in the HTML with only thedeps
array changing, thedidHandlerIdChange
anddidConnectedDragSourceChange
will evaluate to false since it is the same element. However, we expect thedidDragSourceOptionsChange
evaluation to be true, since the source options did in fact change due to the change in thedeps
array.The
didDragSourceOptionsChange
does a key-by-key object comparison though using a customshallowEqual
implementation. This causes the evaluation ofdidDragSourceOptionsChange
to be false even the reference changed due to the change indeps
in theuseDrag
hook.The workaround I did for now is that I added the values of my
deps
array as keys in thespecOptions
object. So for example, my code looks like this:Having the dependencies in the options object ensures that the
didDragSourceOptionsChange
function evaluate to true when theconnector.reconnect()
is called when theuseDrag
hook is updated.My suggestions to a fix for this issue would be either:
==
inside thedidDragSourceOptionsChange
function to account for the options reference changed. This would ensure the reavluation happens whenever the source options change whenever the hook is re-evaluated due to any of its dependencies changing. The source options would never change anyway since the default deps value is an empty array.didChange
variable value.@omarsourour THANK YOU! This was pretty frustrating to debug, but your solution works great.
Would be great to get this fix merged now that were on 2 major versions past this issue 😕