Skip to content

Commit 23cc131

Browse files
authored
fix: hover/drop race conditions
don't run hover animation frame after the drag has ended Description: It's a copy of PR: frontend-collective#841 I think I've found two race conditions where dragging nodes too quickly results in errors. Case 1: Uncaught TypeError: Cannot read property 'path' of null at dnd-manager.js:240 How to reproduce: Open the "Minimal implementation" storybook in Chrome (I have reproduced this in Firefox, too, but it's a lot trickier) Enable 6x slowdown CPU throttling from DevTools Drag-and-drop the nodes around, trying to keep each drag as quick as possible Eventually you'll get error (in DevTools console) "Uncaught TypeError: Cannot read property 'path' of null at dnd-manager.js:240" Apparently what happens is that the animation frame code gets called after the drag is already over, and monitor.getItem() returns null. Case 2: Encountered two children with the same key warning from React How to reproduce: Open the "Callbacks" storybook (important: it has getNodeKey which uses ids) with Chrome Enable 6x slowdown CPU throttling from DevTools Drag-and-drop the nodes around, trying to keep each drag as quick as possible Eventually you'll get Warning: Encountered two children with the same key, 'nodeA'. from React It looks like drop has been called (so the dragged node has been added back to tree), but after the same animation frame code runs, "draggedNode" is set to the already-dropped node... which is then rendered again, and for a short duration (not visible), there are two nodes with same key in the tree...
1 parent 52f0bcf commit 23cc131

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

Diff for: src/utils/dnd-manager.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,14 @@ export default class DndManager {
235235
// throttle `dragHover` work to available animation frames
236236
cancelAnimationFrame(this.rafId);
237237
this.rafId = requestAnimationFrame(() => {
238+
const item = monitor.getItem();
239+
// skip if drag already ended before the animation frame
240+
if (!item || !monitor.isOver()) {
241+
return;
242+
}
238243
this.dragHover({
239244
node: draggedNode,
240-
path: monitor.getItem().path,
245+
path: item.path,
241246
minimumTreeIndex: dropTargetProps.listIndex,
242247
depth: targetDepth,
243248
});

0 commit comments

Comments
 (0)