0

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>
        )
    }
}
10 Rep
  • 2,217
  • 7
  • 19
  • 33
Elliptica
  • 3,928
  • 3
  • 37
  • 68

2 Answers2

5

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

Anna Miroshnichenko
  • 1,143
  • 1
  • 7
  • 24
  • Thank you! I'm new to React and Visual Studio Code, is there a way for it to tell me if there's a typo like that? I know other IDEs I've used will say when a function doesn't exist, but this doesn't seem to. – Elliptica Aug 14 '20 at 20:14
2

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.

  • This easily could've been a comment rather than a question. – Luis Deras Jul 19 '21 at 22:43
  • 2
    I cannot comment yet :( I can comment on my own answer but I don't have comment-on-other-questions-or-answers privileges... – Emily Jablonski Jul 19 '21 at 22:47
  • @EmilyJablonski Thank you for your suggestion! Regarding answer vs comment, what you might do then is once you have enough reputation (it doesn't take long), repeat what you wrote here as a comment reply to the relevant comment, and then delete the answer itself. That is more appropriate since your answer is regarding the question posed in the comment, not really the main question itself. – Elliptica Jul 19 '21 at 23:27