react-beautiful-dnd icon indicating copy to clipboard operation
react-beautiful-dnd copied to clipboard

Add debug helper for missing keys

Open Maxi-Di-Mito opened this issue 5 years ago • 19 comments

Hi, I have this repo https://github.com/Maxi-Di-Mito/dnd-test with some dinamic dragable components using HOCs. There a problem with de DnD that throws this error: react-beautiful-dnd Unable to find draggable with id: FU9fcUhJC👷‍ This is a development only message. It will be removed in production builds.

I can DnD consecutive indexes, i mean from 0 to 1, from 2 to 1 etc..., but when i DnD from 2 to 0 it breaks, and then i cant drag some element anymore.

Maxi-Di-Mito avatar Dec 18 '19 19:12 Maxi-Di-Mito

Hi @Maxi-Di-Mito,

Thanks for raising this issue! Can you please create a standalone example on codesandbox.io using our boilerplate: https://codesandbox.io/s/k260nyxq9v Without a standalone example, we will not be able to action this one Cheers!

danieldelcore avatar Dec 19 '19 04:12 danieldelcore

Thank you @danieldelcore . Here it is, i hope it is ok: https://codesandbox.io/embed/vertical-list-zfcrq?fontsize=14&hidenavigation=1&theme=dark

Maxi-Di-Mito avatar Dec 19 '19 13:12 Maxi-Di-Mito

I am facing the same issue as described by @Maxi-Di-Mito .

wpmonks avatar Jan 02 '20 11:01 wpmonks

I am also facing this issue.

It seems to be caused by draggableAPI.update. When changing the order it gets run twice. On the first run it removes one of the elements from the entries and overwrites the second one. On the second run it should add back the deleted entry, but it does not, because the unique IDs don't match.

siilike avatar Jan 05 '20 00:01 siilike

Problem solved: one of the elements was missing the "key" property, so make sure the keys are always consistent.

siilike avatar Jan 05 '20 14:01 siilike

@siilike can you please elaborate a bit more? what element was missing the "key" property? the Draggable component? If you have a code example it would be very helpful.

orgoldfus avatar Jan 06 '20 19:01 orgoldfus

The code was something along those lines:

const Element = props => (<Draggable index={props.idx} draggableId={""+props.id}>...</Draggable>)

const Container = props => (
	<Droppable droppableId={this.props.droppableId} isDropDisabled={this.props.disabled}>
		{(provided, snapshot) => (
			<div
				ref={provided.innerRef}
				{...provided.droppableProps}
				className={snapshot.isDraggingOver ? 'dragover' : ''}
			>
				<div>
					{data.map((a, idx) => <Element idx={idx} {...a} />)}
				</div>

				{provided.placeholder}
			</div>
		)}
	</Droppable>
)

The error is that

{data.map((a, idx) => <Element idx={idx} {...a} />)}

would have to be:

{data.map((a, idx) => <Element key={a.id} idx={idx} {...a} />)}

Otherwise React will reuse the elements upon reordering the items so that it will confuse the draggableAPI update algorithm. The key has to be unique to that element and stay constant.

siilike avatar Jan 06 '20 20:01 siilike

React should warn you if you are doing this. Would it be worth rbd adding a warning as well?

alexreardon avatar Jan 07 '20 02:01 alexreardon

Yes, there is a warning and the key should be set, but it is not immediately obvious that it affects sorting that way and gives an impression that it is a bug. The easiest would be to just add it to the "Unable to find draggable with id" message.

siilike avatar Jan 07 '20 08:01 siilike

I'll see if I can add some more helpful debugging information

alexreardon avatar Jan 09 '20 04:01 alexreardon

We cannot really tell if the draggable component is supposed to have a key or not. Technically you can wrap a Draggable in other components. In which case they would need to have the key on it.

So from a draggable we cannot tell if a missing key is correct / incorrect

alexreardon avatar Jan 10 '20 01:01 alexreardon

Side comment guys, I had the same issue because I accidentally passed different things to the draggableId and key. It did work the first element, but later if I try to move the first element, it said it can not found.

Specifically (see key={index} below):

<DragDropContext onDragEnd={this.handleDragEnd}>
  <Droppable droppableId="options">
    {(provided) => (
      <div {...provided.droppableProps} ref={provided.innerRef}>
        { this.state.options.map((option, index) =>
          <Option key={index} option={option} ...

and (see draggableId={this.props.option})

export default class Option extends React.Component<OptionProps, OptionState> {
  render() {
    I18n.setLanguage(this.context.language);
    I18n.putVocabularies(strings);

    return (
      <Draggable draggableId={this.props.option} index={this.props.index}>

The problem gets solved once I adjust the key to match the draggable, i.e.: <Option key={option} Hope it can help.

ignaciolarranaga avatar Sep 19 '20 16:09 ignaciolarranaga

Side comment guys, I had the same issue because I accidentally passed different things to the draggableId and key. It did work the first element, but later if I try to move the first element, it said it can not found.

Specifically (see key={index} below):

<DragDropContext onDragEnd={this.handleDragEnd}>
  <Droppable droppableId="options">
    {(provided) => (
      <div {...provided.droppableProps} ref={provided.innerRef}>
        { this.state.options.map((option, index) =>
          <Option key={index} option={option} ...

and (see draggableId={this.props.option})

export default class Option extends React.Component<OptionProps, OptionState> {
  render() {
    I18n.setLanguage(this.context.language);
    I18n.putVocabularies(strings);

    return (
      <Draggable draggableId={this.props.option} index={this.props.index}>

The problem gets solved once I adjust the key to match the draggable, i.e.: <Option key={option} Hope it can help.

This solved my issue. The draggableId should match the key of the component Thanks man.

Frontend-io avatar Nov 13 '20 18:11 Frontend-io

@siilike thanks man! you saved my 2 hours.

alii13 avatar Dec 03 '20 09:12 alii13

The code was something along those lines:

const Element = props => (<Draggable index={props.idx} draggableId={""+props.id}>...</Draggable>)

const Container = props => (
	<Droppable droppableId={this.props.droppableId} isDropDisabled={this.props.disabled}>
		{(provided, snapshot) => (
			<div
				ref={provided.innerRef}
				{...provided.droppableProps}
				className={snapshot.isDraggingOver ? 'dragover' : ''}
			>
				<div>
					{data.map((a, idx) => <Element idx={idx} {...a} />)}
				</div>

				{provided.placeholder}
			</div>
		)}
	</Droppable>
)

The error is that

{data.map((a, idx) => <Element idx={idx} {...a} />)}

would have to be:

{data.map((a, idx) => <Element key={a.id} idx={idx} {...a} />)}

Otherwise React will reuse the elements upon reordering the items so that it will confuse the draggableAPI update algorithm. The key has to be unique to that element and stay constant.

This answer solved the issue for me, just add key prop to your draggable component with the same value as the element id.

OlegSaidov avatar Feb 09 '21 07:02 OlegSaidov

Please solve this. There is no comprehensible reason why "key" and "draggableId" must be the same value. Cost me 2 hours to find out why there are "consecutive key" and "id not found" errors all over the place. While we're at it: I consider the necessity to provide consecutive indexes to the component superfluous - why should this be required for a user to provide? The library should maintain these indexes - at least if they are not provided.

Apart from that, its a very good library and it saved me some days after all.

martin19 avatar May 14 '21 10:05 martin19

Problem solved: one of the elements was missing the "key" property, so make sure the keys are always consistent.

This solved to error for me 🎉🎉. Thanks !

dikshit-n avatar Jun 29 '21 06:06 dikshit-n

Everything is correct in my code as described above, but it's not working. Then i tried after removing strict mode and it starts working, why it's not working with strict mode?

Kuldeep-truefan avatar Jan 15 '24 11:01 Kuldeep-truefan