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

Uncaught Error: Invariant Violation: Expected to find a valid target. #236

Closed
kraftwer1 opened this issue Jul 17, 2015 · 30 comments
Closed

Comments

@kraftwer1
Copy link
Contributor

I've implemented a sortable list and another list to drag items from into that sortable list. The app works as expected. But when I try to move around items that have initially been in that sortable list, I get the following error:

Uncaught Error: Invariant Violation: Expected to find a valid target
.n @ app.js:50803
t.canDropOnTarget @ app.js:50804
(anonymous function) @ app.js:50804
t.handleTopDragEnter @ app.js:50804

I have no idea where to start, because the code works reliably and I only have a the minified version dist/ReactDnD.min.js.

Any hint? What could be a typical for causing this error?

@vkbansal
Copy link
Contributor

Can you share your code?

@gaearon
Copy link
Member

gaearon commented Jul 17, 2015

Yeah, please put up the runnable code somewhere.
It would also help a lot of you could use the version on NPM so it'd be easier to debug the issue.

@kraftwer1
Copy link
Contributor Author

I found the error while setting up an example for you guys. The object that I returned in beginDrag didn't contain an id. Probably React had an issue with that, which might have caused that error in React-Dnd.

@gaearon
Copy link
Member

gaearon commented Jul 19, 2015

Interesting, thanks! We don't really impose any restrictions on what beginDrag() returns as long as it's a plain object so I wonder what the error flow was.

@yannisbarlas
Copy link

Sorry for adding to an old thread, but since this is the only reference to this error on all of the internet, I thought someone might find the following useful in the future.

I had the same error, but the issue was that I had a component (similar to Card in the examples) that was decorated with both drag and drop wrappers.

When simulateBeginDrag began, it sent the drop target (instead of the drag source) to the validator, which correctly failed. The solution was to go one level deep ( with getDecoratedComponentInstance() ) when getting the handler id.

@zekedroid
Copy link

@yannisbarlas great find. I ran into the same exact issue. Maybe there can be a mention of this in the testing docs?

@prakhar1989
Copy link

@yannisbarlas Thanks a ton for the find! Greatly helped me tons of frustration :)

@mariomc
Copy link

mariomc commented Jun 10, 2018

Just in case someone stumbles on this error and issue, I had a similar issue when composing a sortable list and each item having a key composed of the concatenation of its id and its index on the list.
The fix was simply done by setting a proper (ie, consistent) key for the element being dragged.

@damiangreen
Copy link

@yannisbarlas Do you have a code example of your solution?

@yannisbarlas
Copy link

Sorry for the late response @damiangreen, the notification email flew right past me.

The code has been deprecated (it's been a while), but you can check it out here.

@chulanovskyi
Copy link

chulanovskyi commented Feb 10, 2019

If someone still runs in this issue, please note that the element of the list you are mapping by needs to have a persistent key prop. In my case I was dispatching a Redux action to change the items in list, and then providing the key to the mapped element like this:

blocks.map((block, idx) => {
  <React.Fragment key={`${block.name}_${idx}`}>
    ...
  <React.Fragment />
})

which apparently fires the error, because the idx is changing on-the-fly.

@omgoshjosh
Copy link

thanks @chulanovskyi
for me it looked like this:

arr.map((item, idx) => (
    <Item
        item={item}
        // key={`${idx}_${item.id}`} // this was busted because idx
        key={item.key} // when adding this to the array elsewhere i use a count for uniqueness
        index={idx}
    >
    </Item>
))```

@sekoyo
Copy link

sekoyo commented Nov 5, 2019

For me this error is caused by dynamically created drop areas - when the last item is moved from a drop area React re-renders without that area and this seems to cause the exception. Perhaps it's a race condition where the area is removed just before moving the item though the groups are derived from the same items change hmm

@raymond-ong
Copy link

For me this error is caused by dynamically created drop areas - when the last item is moved from a drop area React re-renders without that area and this seems to cause the exception. Perhaps it's a race condition where the area is removed just before moving the item though the groups are derived from the same items change hmm

Hi @dominictobias
I also have dynamically created drop areas.
How did you fix it?

@idMolotov
Copy link

@raymond-ong

I also have dynamically created drop areas.
How did you fix it?

In other words the problem can be that you've created parent (upper level) component again.
In this case react-dnd lost id (his inner id) it has working with and output error.

In my case it was, that I've updated id parameter of the parent entity when update state in the reducer (move columns within row, and update row id when columns change their places). After removing updating id functionality everything starts working correctly.

@dukoo
Copy link

dukoo commented Jul 15, 2020

I also have this issue. In my case it only happens when drop target returns false on canDrop. Can anyone post your solution to this problem? Someone mentioned that it's related to missing ID, but I'm not sure where to put the id?

@leftdevel
Copy link

leftdevel commented Aug 2, 2020

I'm facing the same issue, I managed to tweak an example from the docs, you can see it here by dragging/dropping around the first element: https://codesandbox.io/s/broken-feather-qf0f2?file=/src/Container.jsx

I also created an issue with all the details (maybe I should have just posted here?) #2693

@marcelomrtnz
Copy link

I had the same problem, and I fixed it like this:

my code looked like

const ParentOfCards = () => {    
   
     const [ cards, setCards ] = useState([ ... ])

    const CardComponent = ({ card, index }) => {
       return (/**/)
    }
    return (
        <div>
            { cards.map( CardComponent ) }
        </div>
    )
    
}

it turns out you can't put CardComponent inside ParentOfCards ( I think it has to do with re-renders ), so I solved it separating CardComponent from the ParentOfCards scope:

const ParentOfCards = () => {    
   
     const [ cards, setCards ] = useState([ ... ])

    
    return (
        <div>
            { cards.map( CardComponent ) }
        </div>
    )
    
}

const CardComponent = ({ card, index }) => {
       return (/**/)
}

And now ( after two days of debugging :c ) it works! 😁

@mejayantpatil
Copy link

@marcelomrtnz Thank you so much
You saved my lot of time on this issue on mobile

I was facing same issue while drag drop on mobile with react dnd lib but after removing row column divs from list and keeping only cards list it worked for me without this error. It got that valid target on mobile browser

I got this idea from your post so thank you @marcelomrtnz

@SHAGGYER
Copy link

I have the same issue. https://codesandbox.io/s/proud-wind-hklt6?file=/src/CreateForum.jsx
Here is sandbox. drag item 1ba over item 1, and then item 1ba down again.

@xaptronic
Copy link

Same issue, I had components being defined inside other components (setting up a new app) - took definitions out of being inside each other and resolved. Maybe it has to do with being inside the DndProvider?

@MarkFuller1
Copy link

Very simple example of the problem, move any box and the error is fired, any idea how to fix this?
https://codesandbox.io/s/shy-moon-3q33r?file=/src/Container.jsx

@PabloCorso
Copy link

Very simple example of the problem, move any box and the error is fired, any idea how to fix this?
https://codesandbox.io/s/shy-moon-3q33r?file=/src/Container.jsx

Try adding the key={card.id} prop to the Grid instance instead of the Card inside the renderCard function. Always add a unique key to the component that is directly being used in a map function. This seems to solve the issue.

Funny enough I have this same problem in my code and cannot solve it, got slight more complex code with virtualised list :<

@GNARGNARDAVE
Copy link

I added a debounce to the hover handler (with trailing option) and that solved the issue. The components were updating too quickly by setting the state before DnD could catch up, and the target ID had changed by the time the user dropped the item. So for those of you that could get the above solutions to work, maybe this may help.

@gsoldatov
Copy link

Got this error from conditionally rendered drop targets nested in another drop target. When render condition of the child changed to false during an active drag, its collecting function was occasionally called after the component itself was unmounted.

Fixed the issue by removing conditional rendering of nested components and using display: none when they should not be visible.

@kenlyon
Copy link

kenlyon commented Oct 28, 2021

Wow, this is quite a thread. There are many errors caused by a variety of things described here.

Mine seems caused by re-rendering of my DropTarget component while hovering or dropping on it.

In my use case, I was doing things in the hover() and drop() functions which resulted in the drop target component being re-rendered. Consequently, it seems the target associated with the current drag operation is lost. A subsequent use of monitor.isOver() or monitor.canDrop() in the collect function throws an exception as a result.

My current workaround is to wrap my action in the drop() function in requestAnimationFrame() although setTimeout() would work too. Essentially, I'm delaying the re-rendering until after the drop operation has finished.

My use case doesn't seem so odd. I wonder if there's a better way of avoiding this.

I have a column of items in a toolbox that can be dropped into a form. (e.g. Add a text box to a questionnaire.)

Ideally the hover would be showing a preview of the dragged item in its prospective location until dropped.

The next best thing would be for the preview to be a generic placeholder although this may still cause the same re-render.

UPDATE: The re-rendering of the component wasn't directly the problem. I discovered that I was retaining a reference to the object produced by beginDrag() which seems to have been the real problem. I'm going to change to pass the bare minimum instead and avoid keeping references to it.

@beewolf233
Copy link

hello, I have face this question now, can you give a correct example in this issue??

@GNARGNARDAVE
Copy link

hello, I have face this question now, can you give a correct example in this issue??

Add a debounce to the hover handler.

@WaqasE
Copy link

WaqasE commented Aug 12, 2022

Wow, this is quite a thread. There are many errors caused by a variety of things described here.

Mine seems caused by re-rendering of my DropTarget component while hovering or dropping on it.

In my use case, I was doing things in the hover() and drop() functions which resulted in the drop target component being re-rendered. Consequently, it seems the target associated with the current drag operation is lost. A subsequent use of monitor.isOver() or monitor.canDrop() in the collect function throws an exception as a result.

My current workaround is to wrap my action in the drop() function in requestAnimationFrame() although setTimeout() would work too. Essentially, I'm delaying the re-rendering until after the drop operation has finished.

My use case doesn't seem so odd. I wonder if there's a better way of avoiding this.

I have a column of items in a toolbox that can be dropped into a form. (e.g. Add a text box to a questionnaire.)

Ideally the hover would be showing a preview of the dragged item in its prospective location until dropped.

The next best thing would be for the preview to be a generic placeholder although this may still cause the same re-render.

UPDATE: The re-rendering of the component wasn't directly the problem. I discovered that I was retaining a reference to the object produced by beginDrag() which seems to have been the real problem. I'm going to change to pass the bare minimum instead and avoid keeping references to it.

I'm still facing this issue, how did you fix it? this is my drop.
const [{ isOver }, drop] = useDrop(() => ({
accept: "JSON",
drop: (item) => addDataToCycle(item),
collect: (monitor) => ({
isOver: !!monitor.isOver(),
}),
}));

@percyhanna
Copy link

I was running into the exact same issue as above, and this thread definitely helped my find the root cause, but I wanted to share my specific scenario.

In my case, I was rendering a sort of "empty state" for a list of items, and then if you dragged/hovered an item over this empty state, it would re-render to show a preview of the dragged items, which would then remove the drop handler that was over the empty state. It seems that the drop handler was being removed immediately while hovering, and then react-dnd was trying to hover/drag over a drop handler that no longer existed. The solution was to instead simply hide this empty state rather than completely unmount it/replace it with the hover items.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests