Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: don't lose drag source/preview if disconnected and immediately reconnected #3565

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions .yarn/versions/42579e0f.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
releases:
react-dnd: patch

declined:
- react-dnd-documentation
- react-dnd-examples
- test-suite-cra
- test-suite-vite
- react-dnd-test-utils
12 changes: 8 additions & 4 deletions packages/react-dnd/src/internals/SourceConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export class SourceConnector implements Connector {
private dragPreviewOptionsInternal: DragPreviewOptions | null = null
private dragPreviewUnsubscribe: Unsubscribe | undefined

private isDragSourceConnected = false
private isDragPreviewConnected = false
private lastConnectedHandlerId: Identifier | null = null
private lastConnectedDragSource: any = null
private lastConnectedDragSourceOptions: any = null
Expand Down Expand Up @@ -118,7 +120,7 @@ export class SourceConnector implements Connector {
return didChange
}

if (didChange) {
if (didChange || !this.isDragSourceConnected) {
this.lastConnectedHandlerId = this.handlerId
this.lastConnectedDragSource = dragSource
this.lastConnectedDragSourceOptions = this.dragSourceOptions
Expand All @@ -127,6 +129,7 @@ export class SourceConnector implements Connector {
dragSource,
this.dragSourceOptions,
)
this.isDragSourceConnected = true
}
return didChange
}
Expand All @@ -152,7 +155,7 @@ export class SourceConnector implements Connector {
return
}

if (didChange) {
if (didChange || !this.isDragPreviewConnected) {
this.lastConnectedHandlerId = this.handlerId
this.lastConnectedDragPreview = dragPreview
this.lastConnectedDragPreviewOptions = this.dragPreviewOptions
Expand All @@ -161,6 +164,7 @@ export class SourceConnector implements Connector {
dragPreview,
this.dragPreviewOptions,
)
this.isDragPreviewConnected = true
}
}

Expand Down Expand Up @@ -195,15 +199,15 @@ export class SourceConnector implements Connector {
this.dragSourceUnsubscribe()
this.dragSourceUnsubscribe = undefined
}
this.isDragSourceConnected = false
}

public disconnectDragPreview() {
if (this.dragPreviewUnsubscribe) {
this.dragPreviewUnsubscribe()
this.dragPreviewUnsubscribe = undefined
this.dragPreviewNode = null
this.dragPreviewRef = null
}
this.isDragPreviewConnected = false
}

private get dragSource() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,48 @@ describe('SourceConnector', () => {
expect(unsubscribeDragSource).toHaveBeenCalled()
})

it('handles disconnect and immediate reconnect', () => {
const unsubscribeDragSource = jest.fn()
const unsubscribeDragPreview = jest.fn()
backend.connectDragSource.mockReturnValue(unsubscribeDragSource)
backend.connectDragPreview.mockReturnValue(unsubscribeDragPreview)

connector.receiveHandlerId('test')
connector.hooks.dragSource()({})
connector.hooks.dragPreview()({})
expect(backend.connectDragSource).toHaveBeenCalled()
expect(backend.connectDragPreview).toHaveBeenCalled()
expect(unsubscribeDragSource).not.toHaveBeenCalled()
expect(unsubscribeDragPreview).not.toHaveBeenCalled()
backend.connectDragSource.mockClear()
backend.connectDragPreview.mockClear()

connector.disconnectDragSource()
connector.disconnectDragPreview()
expect(backend.connectDragSource).not.toHaveBeenCalled()
expect(backend.connectDragPreview).not.toHaveBeenCalled()
expect(unsubscribeDragSource).toHaveBeenCalled()
expect(unsubscribeDragPreview).toHaveBeenCalled()
unsubscribeDragSource.mockClear()
unsubscribeDragPreview.mockClear()

// Source & preview should be connected after disconnect
connector.reconnect()
expect(backend.connectDragSource).toHaveBeenCalled()
expect(backend.connectDragPreview).toHaveBeenCalled()
expect(unsubscribeDragSource).not.toHaveBeenCalled()
expect(unsubscribeDragPreview).not.toHaveBeenCalled()
backend.connectDragSource.mockClear()
backend.connectDragPreview.mockClear()

// Source & preview should not be connected a second time
connector.reconnect()
expect(backend.connectDragSource).not.toHaveBeenCalled()
expect(backend.connectDragPreview).not.toHaveBeenCalled()
expect(unsubscribeDragSource).not.toHaveBeenCalled()
expect(unsubscribeDragPreview).not.toHaveBeenCalled()
})

it('unsubscribes drag preview when hook is called without node', () => {
const unsubscribeDragSource = jest.fn()
backend.connectDragSource.mockReturnValueOnce(unsubscribeDragSource)
Expand Down