0
votes

I'm trying to replicate the react-beautiful-dnd tutorial step 4: reorder a list. I've copied the code in the tutorial as far as I can see exactly: https://egghead.io/lessons/react-reorder-a-list-with-react-beautiful-dnd

However, when I run react and try to drag the list items, I get errors like: Unable to find draggable element with id: task-1

If I look at the DOM, I can definitely see an element with that id:

enter image description here

enter image description here

I can't figure out what I'm doing wrong. I printed the id to console to check that it's a string, and it is. Thoughts?

INITIAL-DATA.JS

const initialData = {

    tasks : {
        "task-1" : { id : "task-1", content : "Take out garbage"},
        "task-2" : { id : "task-2", content : "Watch show"},
        "task-3" : { id : "task-3", content : "Charge phone"},
        "task-4" : { id : "task-4", content : "Cook dinner"},
    },

    columns : {
        "column-1" : {
            id : "column-1",
            title: "To Do",
            taskIds : ["task-1", "task-2", "task-3", "task-4"]
        }
    },

    columnOrder : ["column-1"]
};

export default initialData;

INDEX.JS

import React from 'react';
import ReactDOM from 'react-dom';
import initialData from "./initial-data";
import Column from "./column";
import { DragDropContext } from 'react-beautiful-dnd';

class App extends React.Component {
    state = initialData;

    // Needs to synchronously update our state to reflect the drag-drop result
    // The only required DragDrop callback
    onDragEnd = result => {

    }
        
    render() {
        return (
            <DragDropContext onDragEnd={this.onDragEnd}>
            {
                this.state.columnOrder.map( (columnId) => {
            
                    const column = this.state.columns[columnId];
                    const tasks = column.taskIds.map( taskId => this.state.tasks[taskId]);

                    return <Column key={column.id} column={column} tasks={tasks} />;

                })
            }
            </DragDropContext>
        )
    }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

COLUMN.JS

import React from "react";
import styled from "styled-components";
import Task from "./task";
import { Droppable } from 'react-beautiful-dnd';

const Container = styled.div`
    margin: 8px;
    border: 1px solid lightgrey;
    border-radius: 2px;
`;
const Title = styled.h3`
    padding: 8px;
    margin: 0px;
`;
const TaskList = styled.div`
    padding: 8px;
`;

export default class Column extends React.Component {
    render() {
        return (
            // Note: Droppables expect their child to be a function that returns a react component
            <Container>
                <Title>{this.props.column.title}</Title>
                <Droppable droppableId={this.props.column.id}> 
                { provided => (
                    // The droppableProps in the provided object (a react-beautiful-dnd object) need to get provided to the object
                    // you want to designate as your droppable
                    // {provided.placeholder} // Needs to be added as a child of the component you designate as the droppable
                    // ref is an attribute of -components. Returns the dom node of the component
                    <TaskList 
                        ref={provided.innerRef}
                        {...provided.droppableProps}
                    >
                        { this.props.tasks.map( (task, index) => <Task key={task.id} task={task} index={index} /> ) }
                        {provided.placeholder}
                    </TaskList>
                )}
                </Droppable>
            </Container>
        )
    }
}

TASK.JS

import React from "react";
import styled from "styled-components";
import { Draggable } from 'react-beautiful-dnd';

const Container = styled.div`
    border: 1px solid lightgrey;
    border-radius: 2px;
    padding: 8px;
    margin-bottom: 8px;
    background-color: white; /* so don't see through when dragging */
`;

export default class Task extends React.Component {
    render() {
        console.log(this.props.task.id)
        console.log(typeof this.props.task.id)
        return (
            // Required draggable props are draggableId and index
            // Note: Draggables expect their child to be a function that returns a react component
            <Draggable draggableId={this.props.task.id} index={this.props.index}>
                { provided => (
                    // The draggbleProps in the provided object (a react-beautiful-dnd object) need to get provided to the object
                    // you want to designate as your draggable
                    // DragHandleProps needs to get applied to the part of that object that you want to use to drag the whole object
                    // ref is an attribute of -components. Returns the dom node of the component
                    <Container
                        ref={provided.innerRef}
                        {...provided.draggbleProps}
                        {...provided.dragHandleProps}
                    >
                        { this.props.task.content }
                    </Container>
                )}
            </Draggable>
        )
    }
}
2

2 Answers

4
votes

There is just a typo in your code: in task.js change {...provided.draggbleProps} to {...provided.draggableProps}

2
votes

As seen above, the issue here was the typo. Per your comment below that answer, you could help avoid this in the future by using Typescript. It would have shown you an error in your editor at the typo, and also given you autocomplete.