Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 30, 2021 12:59 pm GMT

Drag and Drop with React (with no libraries) part 2

Intro

In this tutorial I will show how to make a Drag and Drop component from scratch (no libraries) using React.

I already made a post on Drag and Drop in React, so why make a new one?

Well, many of us learn new things and think we have a good understanding of it. But then we learn more and realize that there was more to know. So I made a new Drag and Drop that uses better methodologies. Enjoy.

Important info

  1. There exists e.dataTransfer which helps with drag and drop functionality, but as we're using React I find using state to be simpler.

  2. Make sure to check out the Code Sandbox. I may add a few things that aren't reflected below, but the code below is complete.

  3. You might know a better way to do this! If you think you can improve the code please comment.

Drag and Drop in HTML5

There are a few new elements that we will be using (we're not using all of the HTML5 Drag and Drop elements).

  1. draggable makes a div draggable (instead of highlighting)
  2. onDragStart fires when you begin to drag
  3. onDragEnter fires ONCE when the dragged div enters another.
  4. onDragOver fires CONTINUOUSLY when dragging over a div
  5. onDrop fires when the mouse click is released

The final 4 of these we will pass to JavaScript to give it the DND logic.

Getting Started.

Let's make a some groups to drag between and some items to be dragged around.

Dnd.js

import React, { useState } from "react";import "./Dnd.scss";export default function Dnd() {  // my groups to be dragged between  const groups = ["group1", "group2", "group3", "noDrop"];  // My items to be dragged around  const initialItems = [    { id: 1, group: "group1", value: "drag 1" },    { id: 2, group: "group1", value: "drag 2" },    { id: 3, group: "group1", value: "drag 3" }  ];  return (    <>      // Creating the group divs       <div className="groups">        {groups.map((group) => (          <div className="group">            <h1 className="title">{group}</h1>            <div>              // Creating our items to drag and drop              {items                .filter((item) => item.group === group)                .map((item) => (                  <div                    key={item.id}                    id={item.id}                    className="item"                    // THIS MAKES THE ITEM DRAGGABLE!!!                    draggable                  >                     // item title                    {item.value}                  </div>                ))}            </div>          </div>        ))}      </div>    </>  );}

Dnd.scss

.groups {  display: flex;  margin: 5px;  padding: 5px;  flex-wrap: wrap;  .group {    margin: 2px;    padding: 20px;    min-height: 16rem;    background-color: green;    .title{      color: white;      padding: 0;      margin-top: 0;    }  }}.item {  background-color: yellow;  color: blue;  margin: 5px;  padding: 5px;  border: 2px green;  cursor: grab;}

This creates something that looks like this:
Image description

Now we'll add the events and event handlers. Make sure to read the comments in the code as that's where the explanations are. I think this is simpler than describing everything.

Hint: The comments are easier to read in the Code Sandbox.

Dnd.js

import React, { useState } from "react";import "./Dnd.scss";export default function Dnd() {  // Initial groups to drag between  const groups = ["group1", "group2", "group3", "noDrop"];  // Initial items to be dragged   const initialItems = [    { id: 1, group: "group1", value: "drag 1" },    { id: 2, group: "group1", value: "drag 2" },    { id: 3, group: "group1", value: "drag 3" }  ];  // Sets the state of the items. I may add an "add" function later  // Can be used to add items  const [items, setItems] = useState(initialItems);  // Data about a things id, origin, and destination  const [dragData, setDragData] = useState({});  // Are we hovering over the noDrop div?  const [noDrop, setNoDrop] = useState("");  // onDragStart we setDragData.  // useState instead of e.dataTransfer so we can transfer more data  const handleDragStart = (e, id, group) => {    setDragData({ id: id, initialGroup: group });  };  // If we enter the noDrop zone the state will be updated  // Used for styling.  const handleDragEnter = (e, group) => {    if (group === "noDrop") {      setNoDrop("noDrop");    }  };  // DND will not work without this.  const handleDragOver = (e) => {    e.preventDefault();  };  // setNoDrop to nothing to return styling to normal  const handleDragLeave = (e) => {    setNoDrop("");  };  // 1. makes copy of items (newItems)  // 2. changes category of the item to its new group  // 3. setItem to our NewItems  const changeCategory = (itemId, group) => {    const newItems = [...items];    newItems[itemId - 1].group = group;    setItems([...newItems]);  };  // 1. setNoDrop in case item was dropped in noDrop  // 2. gets the item id  // 3. doesn't allow drop in noDrop  // 4. changeCategory (see above)  const handleDrop = (e, group) => {    setNoDrop("");    const selected = dragData.id;    if (group === "noDrop") {      console.log("nuh uh");    } else {      changeCategory(selected, group);    }  };  return (    <>      <div className="groups">        {/* iterate over groups */}        {groups.map((group) => (          <div            // change styling if dragging into noDrop zone            className={`${              group === "noDrop" && noDrop === "noDrop" ? noDrop : "group"            }`}            // event handlers            onDragEnter={(e) => handleDragEnter(e, group)}            onDragOver={handleDragOver}            onDragLeave={handleDragLeave}            onDrop={(e) => handleDrop(e, group)}            key={group}          >            <h1 className="title">{group}</h1>            <div>              {/* iterate over items */}              {items                .filter((item) => item.group === group)                .map((item) => (                  <div                    key={item.id}                    id={item.id}                    // change style if dragged over noDrop                    className={`${                      group === "noDrop" && noDrop === "noDrop"                        ? "notAllowed"                        : "item"                    }`}                    // MAKES THE ITEM DRAGGABLE!!!!                    draggable                    // event handler                    onDragStart={(e) => handleDragStart(e, item.id, group)}                  >                    {/* The name of each item */}                    {item.value}                  </div>                ))}            </div>          </div>        ))}      </div>    </>  );}

Dnd.scss

.groups {  display: flex;  margin: 5px;  padding: 5px;  flex-wrap: wrap;  .group {    margin: 2px;    padding: 20px;    min-height: 16rem;    background-color: green;    .title{      color: white;      padding: 0;      margin-top: 0;    }  }  .noDrop {    margin: 2px;    padding: 20px;    min-height: 16rem;    background-color: red;    cursor: not-allowed !important;    .title{      color: white;      padding: 0;      margin-top: 0;    }  }}.item {  background-color: yellow;  color: blue;  margin: 5px;  padding: 5px;  border: 2px green;  cursor: grab;}.notAllowed {  background-color: yellow;  color: blue;  margin: 5px;  padding: 5px;  border: 2px green;  cursor: not-allowed;}

This is what it looks like

Image description

Conclusion

This is the basic gist of it. If you need something simple that works this is it, otherwise feel free to install a library.

Watch it in action! See the Code Sandbox


Original Link: https://dev.to/wolfmath/drag-and-drop-with-react-519m

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To