React-beautiful-dnd: Add debug helper for missing keys

Created on 18 Dec 2019  ·  14Comments  ·  Source: atlassian/react-beautiful-dnd

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.

idea 🤔

Most helpful comment

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.

All 14 comments

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!

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

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.

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

@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.

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.

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

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.

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

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

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.:

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.:

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

@siilike thanks man! you saved my 2 hours.

Was this page helpful?
0 / 5 - 0 ratings