”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 使用 React、Tailwind CSS 和 Dnd-kit 实现拖放来排列/排序项目

使用 React、Tailwind CSS 和 Dnd-kit 实现拖放来排列/排序项目

发布于2024-08-15
浏览:263

Implementing Drag and Drop to Arrange/Sort Items with React, Tailwind CSS, and Dnd-kit

Introduction

Have you ever wondered how applications like Trello or Asana manage their intuitive drag-and-drop interfaces? Imagine you have an application where users need to sort their items easily. Without a smooth drag-and-drop feature, this task can become tedious and frustrating. In this blog post, we’ll explore how to implement a dynamic drag-and-drop functionality using React, Tailwind CSS, and Dnd-kit to create a seamless user experience for arranging and sorting items.

Real-World Problem

In the real world, applications often require users to rearrange items based on priority, status, or other criteria. For instance, a user may need to reorder their ideas quickly during a brainstorming session. Without an efficient drag-and-drop feature, this process could involve cumbersome steps like manually editing item positions or using inefficient move-up/move-down buttons. Our goal is to provide a solution that simplifies this process, making it more intuitive and efficient for users.

Use Case

Let’s consider a use case of a brainstorming tool where users can organize their ideas. Users need the ability to:

  • Add new ideas to a list.

  • Sort and prioritize these ideas by dragging and dropping them into the desired order.

  • Move ideas between different categories (e.g., new ideas vs. old ideas).

To achieve this, we will build a React application using Vite for the project setup, Tailwind CSS for styling, and Dnd-kit for the drag-and-drop functionality. This setup will allow us to create a user-friendly interface that enhances productivity and user experience.

Setting Up the Project

  • Initialize the Vite Project

npm create vite@latest my-drag-drop-app --template react
cd my-drag-drop-app
npm install

  • Install Required Dependencies:

npm install tailwindcss dnd-kit react-hot-toast react-icons

  • Configure Tailwind CSS:

npx tailwindcss init

  • Update tailwind.config.js:
module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  ],
  plugins: [],
}
  • Add Tailwind directives to index.css:
@tailwind base;
@tailwind components;
@tailwind utilities;

Implementing Drag and Drop

App.jsx

The App.jsx file is the main component that sets up the overall layout of the application and manages the global state.

Summary

  • Main component to manage the overall application state.

  • Utilizes useState to handle project data and updates.

  • Incorporates the Header and DragDropArrange components for UI and functionality.

  • Includes Toaster from react-hot-toast for notifications.

Key Functions:

  • State Management: Manages state for project data.

  • Handle New Data: Function to add new data to the project data state.

  • Layout: Sets up the layout including header, main content, and notifications.

import React, { useState } from 'react';
import { Toaster } from 'react-hot-toast';
import Header from './screens/Navigation/Header';
import DragDropArrange from './screens/DDA/DragDropArrange';
import projectDataJson from "./Data/data.json"

function App() {

  const [projectData, setProjectData] = useState(projectDataJson)
  function handleNewData(data){
    const tempData = projectData.newIdea;
    const maxNumber = (Math.random() * 100) * 1000;
    tempData.push({_id: maxNumber, idea: data});
    setProjectData({...data, newIdea: tempData})
  }

  return (
    
); } export default App;

Header.jsx

The Header.jsx file serves as the navigation bar, providing a button to open a form for adding new items.

Summary:

  • Contains navigation and a button to open the item input form.

  • Uses useState to manage the state of the item input form visibility.

  • Handles user interactions for adding new items.

Key Functions:

  • Item Form Toggle: Manages the visibility of the item input form.

  • Handle New Data: Passes the new item data to the parent component.

import React, { useState } from 'react';
import { PiNotepadFill } from "react-icons/pi";
import AddIdea from '../DDA/AddIdea';

const Header = ({handleNewData}) => {
  const [ideaTabOpen, setIdeaTabOpen] = useState(false)
  return (
    
      
      {ideaTabOpen && (
        
)} > ) } export default Header

AddIdea.jsx

The AddIdea.jsx file provides the form for adding new items, including validation and submission functionality.

Summary:

  • Component for adding new items to the list.

  • Uses useState to manage form input data and character count.

  • Validates input length and submits new data to the parent component.

Key Functions:

  • Handle Change: Manages form input and character count.

  • Handle Submit: Validates and submits the form data to the parent component.

import React, { useState } from 'react';
import toast from "react-hot-toast";
import { Helmet } from 'react-helmet';

const AddIdea = ({ handleNewData, setIdeaTabOpen }) => {
    const maxLengths = 100;

    const [formData, setFormData] = useState();

    const [remainingChars, setRemainingChars] = useState(80)

    const handleChange = (e) => {
        if (e.target.value.length > maxLengths) {
            toast.error(`${`Input can't be more than ${maxLengths} characters`}`);
        } else {
            setFormData(e.target.value);
            setRemainingChars(maxLengths - e.target.value.length);
        }
    };

    const handleSubmit = (e) => {
        e.preventDefault();
        if (!formData) {
            toast.error(`You don't have an idea.`);
            return
        }
        handleNewData(formData);
        setIdeaTabOpen(false)
    };

    return (
        

{remainingChars} characters remaining

Drag Drop & Arrange | New Idea
setIdeaTabOpen(false)}>
); }; export default AddIdea;

DragDropArrange.jsx

The DragDropArrange.jsx file is responsible for managing the drag-and-drop functionality and updating the order of items based on user interactions.

Summary:

  • Main component for handling drag-and-drop functionality.

  • Uses DndContext and SortableContext from @dnd-kit/core for drag-and-drop behavior.

  • Manages state for the data array and updates the order of items based on drag events.

  • Fetches initial data from projectData and sets it to the state.

Key Functions:

  • Handle Drag End: Manages the logic for rearranging items based on drag-and-drop actions.

  • Fetch Data: Fetches initial data and sets it to the component state.

import React, { useState, useEffect } from 'react';
import { DndContext, closestCenter } from '@dnd-kit/core';
import { arrayMove, SortableContext } from '@dnd-kit/sortable';
import { Helmet } from 'react-helmet';
import Arrange from './Arrange';
import Loader from '../Navigation/Loader';

const DragDropArrange = ({projectData}) =>  {
  const [dataArray, setDataArray] = useState({
    newIdea: undefined,
    oldIdea: undefined,
    updateValue: []
  });

  const handleDragEnd = ({ active, over }) => {
    if (!over) return;

    const { fromList, targetId } = active.data.current;
    const { toList, index } = over.data.current;

    if (fromList === toList) {
      const sortedItems = arrayMove(dataArray[toList], dataArray[toList].findIndex((idea) => idea._id === targetId), index);
      setDataArray((prev) => ({ ...prev, [toList]: sortedItems }));
    } else {
      const draggedItem = dataArray[fromList].find((idea) => idea._id === targetId);
      const updatedFromList = dataArray[fromList].filter((idea) => idea._id !== targetId);
      const updatedToList = [...dataArray[toList].slice(0, index), draggedItem, ...dataArray[toList].slice(index)];

      setDataArray((prev) => ({ ...prev, [fromList]: updatedFromList, [toList]: updatedToList }));
    }
  };

  const fetchData = async () => {
    const { newIdea, oldIdea } = projectData;
    setTimeout(() => {
      setDataArray((prev) => ({ ...prev, newIdea, oldIdea }));
    }, 500);
  };

  useEffect(() => {
    fetchData();
  }, []);

  return (
    
{dataArray.newIdea && dataArray.oldIdea && ( )} {!dataArray.newIdea && !dataArray.oldIdea && (
Loading...
> )}
Drag Drop & Arrange | Home
); }; export default DragDropArrange

Arrange.jsx

The Arrange.jsx file handles the arrangement of new and old ideas, displaying them in sortable contexts.

Summary:

  • Manages the arrangement of new and old ideas.
  • Uses SortableContext for sortable behavior.

  • Displays items and manages their order within each category.

Key Functions:

  • Display Items: Renders items in their respective categories.

  • Handle Sorting: Manages the sortable behavior of items.

import React from 'react';
import { SortableContext } from '@dnd-kit/sortable';
import Drag from "./Drag";
import Drop from "./Drop";
import Lottie from 'react-lottie';
import NoData from '../../Lottie/NoData.json';

const Arrange = ({ dataArray }) => {
  const { newIdea, oldIdea } = dataArray;

  const defaultOptions = {
    loop: true,
    autoplay: true,
    animationData: NoData,
    rendererSettings: {
      preserveAspectRatio: "xMidYMid slice"
    }
  };

  return (
    

New Idea

item._id)}> {newIdea.length > 0 && ( {newIdea?.map((data) => ( ))} > )} {newIdea.length
> )}

Old Idea

item._id)}> {oldIdea.length > 0 && ( {oldIdea?.map((data) => ( ))} > )} {oldIdea.length
> )}
); } export default Arrange

Drag.jsx

The Drag.jsx file manages the draggable items, defining their behavior and style during the drag operation.

Summary:

  • Manages the behavior and style of draggable items.

  • Uses useDraggable from @dnd-kit/core for draggable behavior.

  • Defines the drag and drop interaction for items.

Key Functions:

  • useDraggable: Provides drag-and-drop functionality.

  • Style Management: Updates the style based on drag state.

import React from 'react';
import { useDraggable } from '@dnd-kit/core';
import { IoMdMove } from "react-icons/io";

const Drag = ({ data, listType }) => {

    const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({
        id: data._id,
        data: { fromList: listType, targetId: data._id },
    });

    const style = {
        transform: transform ? `translate3d(${transform.x}px, ${transform.y}px, 0)` : undefined,
        opacity: isDragging ? 0.5 : 1,
        pointerEvents: isDragging ? 'none' : 'auto',
    };

    return (
        
            

{data?.idea}

> ); }; export default Drag;

Drop.jsx

The Drop.jsx file defines the droppable areas where items can be dropped, including visual feedback during the drag operation.

Summary:

  • Manages the behavior of droppable areas.
  • Uses useDroppable from @dnd-kit/core for droppable behavior.

  • Provides visual feedback during drag-and-drop interactions.

Key Functions:

  • useDroppable: Provides droppable functionality.

  • Handle Drop: Manages drop actions and updates the state accordingly.

import React from 'react';
import { useDroppable } from '@dnd-kit/core';

const Drop= ({ index, setDragged, listType }) => {
    const { isOver, setNodeRef } = useDroppable({
        id: `${listType}-${index}`,
        data: { toList: listType, index },
    });

    const handleDrop = (e) => {
        e.preventDefault();
        setDragged({ toList: listType, index });
    };

    return (
        
e.preventDefault()} className={`w-auto h-16 rounded-lg flex items-center justify-center text-xs text-secondary_shadow ${isOver ? ` opacity-100` : `opacity-0`}`} style={{ pointerEvents: 'none' }} >
); }; export default Drop

Conclusion

By following this comprehensive guide, you can create a dynamic and user-friendly drag-and-drop interface for your applications. This setup not only enhances user experience but also makes managing and organizing items intuitive and efficient. The combination of React, Tailwind CSS, and Dnd-kit provides a robust foundation for building such interactive features.

Feel free to customize and extend this implementation to suit your specific needs. Happy coding!

Source Code

You can find the complete source code for this project in my GitHub repository:
Github Link

版本声明 本文转载于:https://dev.to/devwithshreyash/implementing-drag-and-drop-to-arrangesort-items-with-react-tailwind-css-and-dnd-kit-2b2f?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    将我的加密库从mcrypt升级到openssl 问题:是否可以将我的加密库从McRypt升级到OpenSSL?如果是这样,如何?答案:是的,可以将您的Encryption库从McRypt升级到OpenSSL。可以使用openssl。附加说明: [openssl_decrypt()函数要求iv参...
    编程 发布于2025-07-13
  • C++中如何将独占指针作为函数或构造函数参数传递?
    C++中如何将独占指针作为函数或构造函数参数传递?
    在构造函数和函数中将唯一的指数管理为参数 unique pointers( unique_ptr [2启示。通过值: base(std :: simelor_ptr n) :next(std :: move(n)){} 此方法将唯一指针的所有权转移到函数/对象。指针的内容被移至功能中,在操作...
    编程 发布于2025-07-13
  • 为什么HTML无法打印页码及解决方案
    为什么HTML无法打印页码及解决方案
    无法在html页面上打印页码? @page规则在@Media内部和外部都无济于事。 HTML:Customization:@page { margin: 10%; @top-center { font-family: sans-serif; font-weight: bo...
    编程 发布于2025-07-13
  • 如何干净地删除匿名JavaScript事件处理程序?
    如何干净地删除匿名JavaScript事件处理程序?
    删除匿名事件侦听器将匿名事件侦听器添加到元素中会提供灵活性和简单性,但是当要删除它们时,可以构成挑战,而无需替换元素本身就可以替换一个问题。 element? element.addeventlistener(event,function(){/在这里工作/},false); 要解决此问题,请考虑...
    编程 发布于2025-07-13
  • Java为何无法创建泛型数组?
    Java为何无法创建泛型数组?
    通用阵列创建错误 arrayList [2]; JAVA报告了“通用数组创建”错误。为什么不允许这样做?答案:Create an Auxiliary Class:public static ArrayList<myObject>[] a = new ArrayList<myO...
    编程 发布于2025-07-13
  • 为什么不使用CSS`content'属性显示图像?
    为什么不使用CSS`content'属性显示图像?
    在Firefox extemers属性为某些图像很大,&& && && &&华倍华倍[华氏华倍华氏度]很少见,却是某些浏览属性很少,尤其是特定于Firefox的某些浏览器未能在使用内容属性引用时未能显示图像的情况。这可以在提供的CSS类中看到:。googlepic { 内容:url(&#...
    编程 发布于2025-07-13
  • 如何使用Python的请求和假用户代理绕过网站块?
    如何使用Python的请求和假用户代理绕过网站块?
    如何使用Python的请求模拟浏览器行为,以及伪造的用户代理提供了一个用户 - 代理标头一个有效方法是提供有效的用户式header,以提供有效的用户 - 设置,该标题可以通过browser和Acterner Systems the equestersystermery和操作系统。通过模仿像Chro...
    编程 发布于2025-07-13
  • 如何从Google API中检索最新的jQuery库?
    如何从Google API中检索最新的jQuery库?
    从Google APIS 问题中提供的jQuery URL是版本1.2.6。对于检索最新版本,以前有一种使用特定版本编号的替代方法,它是使用以下语法:获取最新版本:未压缩)While these legacy URLs still remain in use, it is recommended ...
    编程 发布于2025-07-13
  • 反射动态实现Go接口用于RPC方法探索
    反射动态实现Go接口用于RPC方法探索
    在GO 使用反射来实现定义RPC式方法的界面。例如,考虑一个接口,例如:键入myService接口{ 登录(用户名,密码字符串)(sessionId int,错误错误) helloworld(sessionid int)(hi String,错误错误) } 替代方案而不是依靠反射...
    编程 发布于2025-07-13
  • Python环境变量的访问与管理方法
    Python环境变量的访问与管理方法
    Accessing Environment Variables in PythonTo access environment variables in Python, utilize the os.environ object, which represents a mapping of envir...
    编程 发布于2025-07-13
  • 如何在无序集合中为元组实现通用哈希功能?
    如何在无序集合中为元组实现通用哈希功能?
    在未订购的集合中的元素要纠正此问题,一种方法是手动为特定元组类型定义哈希函数,例如: template template template 。 struct std :: hash { size_t operator()(std :: tuple const&tuple)const {...
    编程 发布于2025-07-13
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中检索一个随机项目,利用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-07-13
  • 如何将MySQL数据库添加到Visual Studio 2012中的数据源对话框中?
    如何将MySQL数据库添加到Visual Studio 2012中的数据源对话框中?
    在Visual Studio 2012 尽管已安装了MySQL Connector v.6.5.4,但无法将MySQL数据库添加到实体框架的“ DataSource对话框”中。为了解决这一问题,至关重要的是要了解MySQL连接器v.6.5.5及以后的6.6.x版本将提供MySQL的官方Visual...
    编程 发布于2025-07-13
  • 如何在GO编译器中自定义编译优化?
    如何在GO编译器中自定义编译优化?
    在GO编译器中自定义编译优化 GO中的默认编译过程遵循特定的优化策略。 However, users may need to adjust these optimizations for specific requirements.Optimization Control in Go Compi...
    编程 发布于2025-07-13
  • 如何有效地转换PHP中的时区?
    如何有效地转换PHP中的时区?
    在PHP 利用dateTime对象和functions DateTime对象及其相应的功能别名为时区转换提供方便的方法。例如: //定义用户的时区 date_default_timezone_set('欧洲/伦敦'); //创建DateTime对象 $ dateTime = ne...
    编程 发布于2025-07-13

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3