Skip to content

Commit

Permalink
fix: "Invariant Violation: Expected targetIds to be registered." (#3409)
Browse files Browse the repository at this point in the history
* fix: "Invariant Violation: Expected targetIds to be registered."

We've sporadically seen this error from customers. The call stack
indicates that it's originating from HTML5BackendImpl's
handleTopDragOver's requestAnimationFrame callback.  I've been unable to
reproduce it locally; however, if I simulate a slowdown by replacing
`requestAnimationFrame(callback)` with `setTimeout(callback, 10000)`, I
can fairly reliably reproduce this error.

To fix it, I believe HTML5BackendImpl should consistently clear the
hover animation whenever the drag operation is ended for any reason.

I locally tested this fix in the v15.1.2 tag, and it appeared to work.

Fixes #763, #3403

* chore: semver

* fix: cancel any raf before creating a new one

Co-authored-by: Chris Trevino <chtrevin@microsoft.com>
  • Loading branch information
joshkel and darthtrevino committed Mar 29, 2022
1 parent 0830641 commit 32b0bbf
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 20 deletions.
6 changes: 1 addition & 5 deletions .github/workflows/ci.yml
Expand Up @@ -28,11 +28,7 @@ jobs:
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn version check
if: "github.actor != 'dependabot[bot]' && !contains(github.ref , 'release/') && !contains(github.head_ref , 'release/')"
name: Version Check

- run: yarn install
name: Install Dependencies

Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/version-check.yml
@@ -0,0 +1,16 @@
name: Version Check
on: [push, pull_request]
env:
DEFAULT_NODE_VERSION: 16
jobs:
version-check:
runs-on: ubuntu-latest
if: "github.ref != 'main' && github.head_ref != 'main' && !contains(github.ref , 'release/') && !contains(github.head_ref , 'release/') && !contains(github.ref , 'dependabot/') && !contains(github.head_ref , 'dependabot/')"
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v1
with:
node-version: ${{env.DEFAULT_NODE_VERSION}}
- run: yarn version check
9 changes: 9 additions & 0 deletions .yarn/versions/e42d7e63.yml
@@ -0,0 +1,9 @@
releases:
react-dnd-html5-backend: patch

declined:
- react-dnd-documentation
- react-dnd-examples
- test-suite-cra
- test-suite-vite
- react-dnd-test-utils
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
@@ -1,6 +1,6 @@
# Contributing to React-DnD

So you want to contibute to React-DnD? Thank you! This library is a community effort, and your contributions are greatly appreciated.
So you want to contribute to React-DnD? Thank you! This library is a community effort, and your contributions are greatly appreciated.

## FAQ

Expand Down
50 changes: 36 additions & 14 deletions packages/backend-html5/src/HTML5BackendImpl.ts
Expand Up @@ -347,6 +347,7 @@ export class HTML5BackendImpl implements Backend {
if (this.clearCurrentDragSourceNode() && this.monitor.isDragging()) {
this.actions.endDrag()
}
this.cancelHover()
}

private setCurrentDragSourceNode(node: Element | null) {
Expand Down Expand Up @@ -400,6 +401,36 @@ export class HTML5BackendImpl implements Backend {
return false
}

private scheduleHover = (dragOverTargetIds: string[] | null) => {
if (
this.hoverRafId === null &&
typeof requestAnimationFrame !== 'undefined'
) {
// cancel any existing hover if present
this.cancelHover()

this.hoverRafId = requestAnimationFrame(() => {
if (this.monitor.isDragging()) {
this.actions.hover(dragOverTargetIds || [], {
clientOffset: this.lastClientOffset,
})
}

this.hoverRafId = null
})
}
}

private cancelHover = () => {
if (
this.hoverRafId !== null &&
typeof cancelAnimationFrame !== 'undefined'
) {
cancelAnimationFrame(this.hoverRafId)
this.hoverRafId = null
}
}

public handleTopDragStartCapture = (): void => {
this.clearCurrentDragSourceNode()
this.dragStartSourceIds = []
Expand Down Expand Up @@ -429,6 +460,7 @@ export class HTML5BackendImpl implements Backend {
// Avoid crashing if we missed a drop event or our previous drag died
if (this.monitor.isDragging()) {
this.actions.endDrag()
this.cancelHover()
}

// Don't publish the source just yet (see why below)
Expand Down Expand Up @@ -530,6 +562,7 @@ export class HTML5BackendImpl implements Backend {
// Only proceed if we have not handled it already.
this.actions.endDrag()
}
this.cancelHover()
}

public handleTopDragEnterCapture = (e: DragEvent): void => {
Expand Down Expand Up @@ -622,20 +655,7 @@ export class HTML5BackendImpl implements Backend {
this.altKeyPressed = e.altKey
this.lastClientOffset = getEventClientOffset(e)

if (
this.hoverRafId === null &&
typeof requestAnimationFrame !== 'undefined'
) {
this.hoverRafId = requestAnimationFrame(() => {
if (this.monitor.isDragging()) {
this.actions.hover(dragOverTargetIds || [], {
clientOffset: this.lastClientOffset,
})
}

this.hoverRafId = null
})
}
this.scheduleHover(dragOverTargetIds)

const canDrop = (dragOverTargetIds || []).some((targetId) =>
this.monitor.canDropOnTarget(targetId),
Expand Down Expand Up @@ -672,6 +692,7 @@ export class HTML5BackendImpl implements Backend {
if (this.isDraggingNativeItem()) {
setTimeout(() => this.endDragNativeItem(), 0)
}
this.cancelHover()
}

public handleTopDropCapture = (e: DragEvent): void => {
Expand Down Expand Up @@ -709,6 +730,7 @@ export class HTML5BackendImpl implements Backend {
} else if (this.monitor.isDragging()) {
this.actions.endDrag()
}
this.cancelHover()
}

public handleSelectStart = (e: DragEvent): void => {
Expand Down

0 comments on commit 32b0bbf

Please sign in to comment.