React-beautiful-dnd: `Non-consecutive index` error when using redux thunk even with array index passed to droppable index

Created on 3 Mar 2020  路  11Comments  路  Source: atlassian/react-beautiful-dnd


I have a droppable list whose list items can be reordered. onDragEnd dispatches a redux thunk action that calls the api and updates the state which gets passed to the component that renders the droppable list. DragDropContext is outside of the component. App will be served via nextjs with server side rendering and resetServerContext() before rendering each page server side.

Expected behavior

On drop the animation takes place, onDragEnd dispatches the action causing the api call, because of the response delay the UI will glitch (no reordering will be rendered), the response returns and the list renders in the correct order.

After that item reordering should still be possible without any glitches, errors, etc.

Actual behavior

After first movement, reordering of the previously moved item is not possible and the console prints

Unable to find draggable with id: {"type":"FoodPlanPosition","foodPlanPositionId":12}

When dragging another item the UI is simply broken and the console prints

Detected non-consecutive <Draggable /> indexes.(This can cause unexpected bugs)0, [馃敟2], 3, 4, 5

The strange thing is that the list items droppable index will be taken from array index which can't get non-consecutive:

                  {props.baseFoodPlanPositions.map((position, idx) => {
                    return (
                      <Draggable
                        key={idx}
                        index={idx}
                        draggableId={buildFoodPlanPositionDraggableId(position.id)}
                      >
                        {(provided, _snapshot) => {
                          return (
                            <ListItem
                              ref={provided.innerRef}
                              {...provided.draggableProps}
                              {...provided.dragHandleProps}
                              button
                              className={classes.dailyFoodPlanPosition}
                            >
                               {position.foodPlanComponent.name}
                            </ListItem>
                          )
                        }}
                      </Draggable>
                    )
                  })}

Even react component inspector and heavy debugging revealed that the dnd draggable and droppable gets their right id and index.
Draggable and Droppable ids are unique (contain database primary key).

In addition I observed strange behavior when adding droppables too fast, whose surrounding components gets rendered via the lifecycle depicted above (click, dispatch, API call, response, stateChange, render). When Items from other lists will be dropped there, they get the wrong droppable ID and therefore will be appended to the wrong list.

This seems to be some kind of race condition and hope anyone can provide a hint where to start. I tried to rebuild the scenario (redux managed list) via code sandbox, but can't emulate API calls and nextjs there.

Steps to reproduce

IMHO too complex to provide currently - If the details provided above are too vague and analysis of the problem is not possible, I'll break things down and provide one.

Current one that uses redux, but no API calls and nextjs, and has no unexpected behavior:
https://codesandbox.io/s/react-redux-material-ui-react-beautiful-dnd-bug-itp55

What version of React are you using?

[email protected]:
  version "16.9.0"

What version of react-beautiful-dnd are you running?

react-beautiful-dnd@^13.0.0:
  version "13.0.0"

What browser are you using?

latest Chrome

Demo

unconfirmed-bug untriaged

Most helpful comment

I was following the tutorial and bump into the same problem.

I just add the key property to my Draggable component and everything start to work as expected.

change from this

<Draggable draggableId={id} index={index}>
            {(provided) => (
                <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
                    <Tile>
                        <p>{id}</p>
                    </Tile>
                </div>
            )}
        </Draggable>

to this

<Draggable key={id} draggableId={id} index={index}>
            {(provided) => (
                <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
                    <Tile>
                        <p>{id}</p>
                    </Tile>
                </div>
            )}
        </Draggable>

All 11 comments

I used the array index as ReactElement key, which lead to the error.

Is it possible to move the hint https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/draggable.md#keys-for-a-list-of-draggable- into the section required-props? After reaching optional pros I just scanned over the site and missed the point of key. Even better to point to the equal important key at the index rule and even at setup problems.

I'm running into the same problem. Did you find a way out by any chance? Thanks! @rolandjohann

Even I am running into same problem. Any way out for this issue?

facing same issue, is fix expected? when?

I am running into the same issue. Has there been a fix for it?

I'm also facing this issue. Any solution?

The OP mentions the solution (see the doc in the 2nd comment)
Moreover, I think the issue is that the tutorial on egghead doesn't specify key for a draggable either - which can potentially lead to a lot of users facing the issue

The OP mentions the solution (see the doc in the 2nd comment)
Moreover, I think the issue is that the tutorial on egghead doesn't specify key for a draggable either - which can potentially lead to a lot of users facing the issue

In the egghead tutorial, the Draggable component is inside the child list component

image

but in the code shown in this issue, the Draggablecomponent is wrapping the child list component.

image

In order to add the key property on the Draggable component, is it better to have the code structure as in the first or second scenario? @yogeshnachnani

I was following the tutorial and bump into the same problem.

I just add the key property to my Draggable component and everything start to work as expected.

change from this

<Draggable draggableId={id} index={index}>
            {(provided) => (
                <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
                    <Tile>
                        <p>{id}</p>
                    </Tile>
                </div>
            )}
        </Draggable>

to this

<Draggable key={id} draggableId={id} index={index}>
            {(provided) => (
                <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
                    <Tile>
                        <p>{id}</p>
                    </Tile>
                </div>
            )}
        </Draggable>

Change this:

<Draggable draggableId={id} index={index}>
            {(provided) => (
                <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
                    <Tile>
                        <p>{id}</p>
                    </Tile>
                </div>
            )}
        </Draggable>

to

<Draggable draggableId={id}  key={id} index={index}>
            {(provided) => (
                <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
                    <Tile>
                        <p>{id}</p>
                    </Tile>
                </div>
            )}
        </Draggable>

Don't use index as the key

Experienced the same problem. Adding item.id as a key to the helped (index did not)

Thanks @spmsupun for pointing out to do not use index as key.

Was this page helpful?
0 / 5 - 0 ratings