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

How to debug "Cannot call hover after drop"? #442

Closed
hakunin opened this issue Apr 19, 2016 · 24 comments
Closed

How to debug "Cannot call hover after drop"? #442

hakunin opened this issue Apr 19, 2016 · 24 comments

Comments

@hakunin
Copy link

hakunin commented Apr 19, 2016

Hi,
one of my coworkers is able to somehow break the monitor state and it thinks its hovering even though the mouse is up and gives him this:

screenshot 2016-04-19 16 34 56

Any ideas on where to start debugging? I can't reproduce it and he sees it once a week.
I am using the touch backend switched to handle mouse events as well with a few tweaks.

@hakunin
Copy link
Author

hakunin commented Apr 19, 2016

So investigated the JS issue I found out that prior to this error, there was an error thrown from a user defined callback when drop is supposed to happen, which then could have broken the state of the monitor/store.

@PendragonDevelopment
Copy link

I'm having this issue as well - my situation is such that the React component is both the drop target and the drag source. When I have two components, I can drag and drop once before it throws the above error. When I have three, it works without an error. I assume it has something to do with the multiple contexts on a single component?

@hueypeard
Copy link

hueypeard commented Apr 28, 2016

I had this problem and I found a workaround for my particular use case last night.

For context, I was rendering a list of DragSources, and if any of those dropped onto a DropTarget they would be removed from the list of DragSources and the DropTarget would be replaced with a component which renders the content of the DragSource.

An essential part of this drag and drop functionality (It's a component to match 'categories' to items) was a feature to add items back to the DragSource list, which would just replace the placed item with a DragSource and add it back to the DragSources list.

image

Now, this exception only occurred when I would place items in all the categories and remove at least one (not when the list wasn't full and I would remove one and add it back again). So I came to the conclusion that the DragSources list could never have zero children for this to occur (possibly due to the container element disappearing but I didn't have enough time to test this). To mitigate this, instead of removing items from the DragSources list on placement, I just set their style to display: none

It's a difficult one to explain, but I hope this helps.

@johndanek
Copy link

I am experiencing the same effect as @PendragonDevelopment. My list starts with one item, gets a second added to it, then can be rearranged. You can only rearrange the two items one time before you start seeing Javascript errors, and you can never reorder them again.

@ehsangazar
Copy link

I have this issue, too
I don't know why but after first rearrangement, I see these errors

@Codenetz
Copy link

Codenetz commented Oct 22, 2016

I got the same error here.

After some comparing the demo example and mine i found that when I loop the Components I use the array key to set component both key and index and in the demo they set only the index Sortable/Simple/Container.js and the key is fixed.

Did it and worked!

The key must be fixed value because if is not the reference to component is loosed after the array reorder.

When you have dynamically component creating and attaching DnD you must use some library or maybe Date.now() will do it for generating unique keys for each component.

{this.state.rows.map(function(row, key) {
  return (<RowComponent key={row.id} index={key} id={row.id} moveRow={that.moveRow} />);
})}

row.id is unique for each component

@siemiatj
Copy link

siemiatj commented Feb 2, 2017

I don't understand why it works, but using my model.id instead of a random key generated by node-uuid's v4 fixed it. At least I'm not getting errors anymore.

@ysfzrn
Copy link

ysfzrn commented Mar 27, 2017

Fixing key didn't solve my problem.
This was my code

           <ContentPatch>
             {tasks.loading 
              ? <div>...loading </div>
              : this.state.containers.map((item, i) => {
                  return (
                    <TaskStage
                      key={item.id}
                      item={item}
                      tasklist={tasks.tasks}
                      onDropped={this.handleDropped}
                      onBeginningDrag={this.onBeginningDrag}
                    />
                  );
                })}
          </ContentPatch>

After every dropped action, I was mapping all items and I was getting same error.
And I changed my condition to

...
{tasks.loading && tasks.tasks.length===0
 ? <div>...loading </div>
...

and it's solved. I think, again again mounting is reason of this error.

@nickdandakis
Copy link

nickdandakis commented Apr 9, 2017

I came across this same error.

My use case was:

  • Same DragSource and DragTarget component
  • On drop, I wanted to navigate to a route

Turns out that endDrag (DragSource method) fires after drop (DropTarget method). I was handling the route navigation within drop which was breaking the monitor's state.

Moved that logic over to endDrag to fix it. Refactoring involved checking if the drop was complete with monitor.didDrop(), but wasn't too bad.

@selkinvitaly
Copy link

I have this issue, too. My case is such that the component is both the drop target and the drag source. I have tried to use endDrag method and tried to use patched backend (https://gist.github.com/nickpresta/eb5cce69d650db4c2795). It didn't solved this problem.

my component:

@DropTarget<HeadColOwnProps>(TaskDndTypes.headCol, headColTargetSpec, headColTargetCollector)
@DragSource<HeadColOwnProps>(TaskDndTypes.headCol, headColSourceSpec, headColSourceCollector)
class HeadColComponent extends React.Component<any, void> {
    render() {
        const props = this.props;
        return this.props.dndConnectDropTarget(
            this.props.dndConnectDragPreview(
                <div>
                    <div className={block('panels-task__drag')({start: props.dndIsDragging})}>
                        <SortingIcon
                            label={props.label}
                            arrowIsVisible={props.sortingIsPossible}
                            direction={props.sortingDirection}
                            clickHandler={props.sortingHandler}
                        />
                        {this.props.dndConnectDragSource(
                            <span className="panels-task__drag-control">
                                <SVGIcon width={10} height={10} url={'#icon-drag-and-drop-cell'} />
                            </span>
                        )}
                    </div>
                </div>
            )
        );
    }
}

Example of use:

const renderHeadCellId = (): JSX.Element => {
        return (
            <TaskCellHead key="key-head-col-id" modifications={{ number: true }}>
                <HeadColComponent
                    label="#"
                    key="key-dnd-head-col-id"
                    taskColType={TaskCols.id}
                    sortingIsPossible={false}
                    taskColsOrder={taskStore.orderCols}
                    updateDragProcess={(dp: TaskColDragProcess | null) => taskStore.updateDragProcess(dp)}
                    updateOrderCols={(order: TaskCols[]) => taskStore.updateOrderCols(order)}
                    dragProcess={taskStore.dragProcess}
                />
            </TaskCellHead>
        );
    };

Decorator settings:

const headColSourceSpec: DragSourceSpec<HeadColOwnProps> = {
    beginDrag(props: HeadColOwnProps): DraggedItem {
        return { sourceColType: props.taskColType };
    },
    canDrag(props: HeadColOwnProps): boolean {
        return props.taskColsOrder.length > 1;
    },
    endDrag(props: HeadColOwnProps, monitor: DragSourceMonitor): void {
        console.debug('endDrag');
        if (!monitor.didDrop()) {
            return;
        }
        console.debug('endDrag finish');
        props.updateOrderCols((monitor.getDropResult() as DroppedResult).newOrderCols);
    }
};

const headColTargetSpec: DropTargetSpec<HeadColOwnProps> = {
    drop(props: HeadColOwnProps, monitor: DropTargetMonitor): DroppedResult {
        console.debug('drop');
        return {
            newOrderCols: getNewOrder((monitor.getItem() as DraggedItem).sourceColType, props.taskColsOrder, props.dragProcess)
        };
    },
    hover(props: HeadColOwnProps, monitor: DropTargetMonitor, component: HeadColComponent): Object | void {
        if (!monitor.canDrop()) {
            return;
        }
        // ...
        props.updateDragProcess(currentDragProcess);
    },
    canDrop(props: HeadColOwnProps, monitor: DropTargetMonitor): boolean {
        return props.taskColType !== (monitor.getItem() as DraggedItem).sourceColType;
    }
};

const headColSourceCollector = (connect: DragSourceConnector, monitor: DragSourceMonitor) => ({
    dndConnectDragSource: connect.dragSource(),
    dndConnectDragPreview: connect.dragPreview(),
    dndIsDragging: monitor.isDragging()
});

const headColTargetCollector = (connect: DropTargetConnector, monitor: DropTargetMonitor) => {
    return {
        dndConnectDropTarget: connect.dropTarget(),
        dndIsOverCurrent: monitor.isOver({ shallow: true })
    };
};

I noticed that after rearrangement endDrag is not called, but drop is called. These lines are never executed:

endDrag(props: HeadColOwnProps, monitor: DragSourceMonitor): void {
        console.debug('endDrag');
        if (!monitor.didDrop()) {
            return;
        }
        console.debug('endDrag finish');
        props.updateOrderCols((monitor.getDropResult() as DroppedResult).newOrderCols);
    }

What am I doing wrong? Any ideas?

@selkinvitaly
Copy link

selkinvitaly commented Apr 10, 2017

I replaced HTML5Backend to Touch Backend (https://github.com/yahoo/react-dnd-touch-backend). It works for me.

@jktravis
Copy link

For me, I was getting this error just for having breakpoints set in the callback on the drop. What is interesting is it would fail even after all breakpoints were continued and the browser wasn't paused. As soon as I removed the breakpoints, the error when away.

@didair
Copy link

didair commented May 10, 2017

Im having the same issue. Replaced this package with react-dnd-touch-backend but that doesn't really help solving the issue. I would rather run html5. Tried setting keys on all elements that is being printed by an iterator.

@nowseemee
Copy link

I was getting the same error. I was re-applying a HOC on the draggable components on every render so they were always different which confused react-dnd.

@richburdon
Copy link

@hakunin did you resolve this (I also only get this error after another runtime error has occurred).

@hakunin
Copy link
Author

hakunin commented Jun 27, 2017

I've since refactored all the DnD code I've got and I still get it when I start dragging. Now that I moved all the code into a single util file and made it configurable, I might be able to finally find the reason it happens at some point. Will post about it here when I do. (I am using TouchBackend in mouse setting btw)

@richburdon
Copy link

Thanks for the response. I only get this error after some other error occurs while dragging -- at which point it seems unrecoverable. is that the same for you?

@hakunin
Copy link
Author

hakunin commented Jun 28, 2017

Mine complains every time I start dragging.

@shawnbissell
Copy link

My case was that the component in endDrag(props, monitor, component) was undefined after the item was dropped. So that was causing my original error which led to the console stream of "Cannot call hover after drop" messages.

@hakunin
Copy link
Author

hakunin commented Jul 28, 2017

I've been able to resolve this issue thanks to this comment: #431 (comment)

@nameliuqi
Copy link

i met this when i caused other uncatched error before.there is no this error when there were no others errors.

@ivanKoretskyy
Copy link

In my case it happened when in endDrag i call some action/function that cause error. So basicaly uncatched error made dnd stuck. you can use try catch when calling some function/action in endDrag block.
endDrag: (props, monitor) => { try { handleEndDrag(); } catch(errror) { console.error(error)} }

@warpdesign
Copy link

warpdesign commented Jul 10, 2019

A debugger statement inside the onDrop function was also the source of the error for me. Removing it makes the error disappear but then I am having a hard time debugging without it.

Any idea why debugger is triggering this error?

Not sure if it's of any interest but I am running an Electron app.

@stale
Copy link

stale bot commented Sep 8, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Sep 8, 2019
@stale stale bot closed this as completed Sep 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests