Drag and Drop In React- Part 1.

Today I would like to go through implementing drag and drop in React without using a separate library.

Let’s dive right in, shall we?

So step 1 will be creating a root app.

import React from 'react';import ReactDOM from 'react-dom';import '.index.css';import AppDragDropDemo from './AppDragDropDemo';ReactDOM.render(<AppDragDropDemo />,     document.getElementById("root"));

Now for entry for the AppDragDropDemo:

import React, { Component } from 'react';export default class AppDragDropDemo extends Component {  
render () {
return (
<div className="container-drag">
DRAG & DROP DEMO
</div> );
}
}

Let’s create some tasks to simulate a simple application. What we intend to do is to drag and drop these tasks into different categories like wip, complete , and so on:

export default class AppDragDropDemo extends Component {             state = {            
tasks: [{name:"Learn Angular",
category:"wip",
bgcolor: "yellow"},
{name:"React",
category:"wip",
bgcolor:"pink"},
{name:"Vue",
category:"complete",
bgcolor:"skyblue"}]
}

Now in the render method, to group tasks into their respective categories, wip and complete:

render() {         
var tasks = { wip: [],
complete: []}

this.state.tasks.forEach ((t) => {
tasks[t.category].push(<div key={t.name}
onDragStart={(e)=>this.onDragStart(e, t.name)}
draggable
className="draggable"
style={{backgroundColor: t.bgcolor}}>
{t.name}
</div>);
});

Add the draggable attribute to the <div> or any element to make an element draggable.

The next step is to create a draggable container.

To create a droppable container, implement the dragover event. Now, since we want to disable the default dragover event, we simple call the event.preventDefault() from the dragover event.

We will also render {tasks.wip} and {tasks.complete} in their corresponding div elements.

return (<div className="container-drag">     
<h2 className="header">DRAG & DROP DEMO</h2> <div className="wip" onDragOver={(e)=>this.onDragOver(e)} onDrop={(e)=>{this.onDrop(e, "wip")}}> <span className="task-header">WIP</span> {tasks.wip}
</div>
<div className="droppable"
onDragOver={(e)=>this.onDragOver(e)}
onDrop={(e)=>this.onDrop(e, "complete")}>
<span className="task-header">COMPLETED</span>
{tasks.complete}
</div>
</div>);

Now we need to capture the state of the element being dragged:

Let’s modify the code where we are creating the category for each task. Add an eventhandler ondragstart and pass the id/name or any information you need to persist while the drag/drop is happening.

Let’s now implement the onDragStart event handler.onDragStart = (ev, id) => {   console.log('dragstart:', id);
ev.dataTransfer.setdata("id", id);
}

In the onDragStart handler, we grab the parameter and store that within the dataTransfer object.

The above handler will ensure that the element being dragged is stored in the event object and is available for use when required. It may be required while dropping on a target.

Now we need to handle the drop event. Let’s open up the render method and add the onDrop event to the div with a className of droppable.

return (
<div className="container-drag">
<h2 className="header">DRAG & DROP DEMO</h2>
<div className="wip" >
<span className="task-header">WIP</span>
{tasks.wip}
</div>
<div className="droppable"
onDragOver={(e)=>this.onDragOver(e)}>
onDrop={(e)=>this.onDrop(e, "complete")}>
<span className="task-header">COMPLETED</span>
{tasks.complete}
</div>
</div>);

In the above code, we add the drop event handler, and pass the required category complete as an argument. This indicates we are dropping the element from the wip state to the complete state (category). Please feel free to change the names, as required.

Let’s now implement the onDrop() event handler.

onDrop = (ev, cat) => { 
let id = ev.dataTransfer.getData("id");
let tasks = this.state.tasks.filter((task) => {
if (task.name == id) {
task.category = cat;
}
return task;
});
this.setState({
...this.state,
tasks
});
}

In the onDrop event handler, we grab the task being dragged by using getData method on the event’s dataTransfer object.

We then create a new tasks array by using the filter method, and change the category of the task being dragged.

setState() will trigger render, and the tasks will be rendered in the right areas.

Now to implement drop from “complete” to “wip,” add the onDrop handler
The onDrop() handler remains the same as earlier:

return (
<div className="container-drag">
<h2 className="header">DRAG & DROP DEMO</h2>
<div className="wip"
OnDrop={(e)=> {this.OnDrop(e, "wip")}}>
<span className="task-header">WIP</span>
{tasks.wip}
</div>
<div className="droppable"
onDragOver={(e)=>this.onDragOver(e)}
onDrop={(e)=>this.onDrop(e, "complete")}>
<span className="task-header">COMPLETED</span>
{tasks.complete}
</div>
</div>);

This is the basic idea of how to do it. Hope you enjoyed!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Kirill Chaim Shcherbina

Kirill Chaim Shcherbina

Passionate Programmer. Independent Thinker. Caring Father. Graduate of Flatiron Bootcamp for Software Development. Currently seeking new opportunities.