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

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

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

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]删除
最新教程 更多>
  • 为什么填充在 Safari 和 IE 选择列表中不起作用?
    为什么填充在 Safari 和 IE 选择列表中不起作用?
    在 Safari 和 IE 的选择列表中不显示填充尽管 W3 规范中没有限制,但 WebKit 浏览器不支持选择框中的填充,包括Safari 和 Chrome。因此,这些浏览器中不应用填充。要解决此问题,请考虑使用 text-indent 而不是 padding-left。通过相应增加选择框的宽度来...
    编程 发布于2024-11-05
  • 在 Spring Boot 中创建自定义注释的终极指南
    在 Spring Boot 中创建自定义注释的终极指南
    Such annotations fill the entire project in Spring Boot. But do you know what problems these annotations solve? Why were custom annotations introduce...
    编程 发布于2024-11-05
  • 为什么 Elixir 在异步处理方面比 Node.js 更好?
    为什么 Elixir 在异步处理方面比 Node.js 更好?
    简单回答:Node.js 是单线程的,并拆分该单线程来模拟并发,而 Elixir 利用了 Erlang 虚拟机 BEAM 原生的并发和并行性,同时执行进程。 下面,我们将更深入地了解这种差异,探索两个关键概念:Node.js 事件循环和 Elixir 的 BEAM VM 和 OTP。这些元素对于理解...
    编程 发布于2024-11-05
  • AngularJS $watch 如何替代动态导航高度调整中的计时器?
    AngularJS $watch 如何替代动态导航高度调整中的计时器?
    避免 AngularJS 的高度监视计时器当导航高度是动态时,AngularJS 程序员经常面临响应式导航的挑战。这就导致需要调整内容的 margin-top 值以响应导航高度的变化。以前,使用计时器来检测导航高度的变化,但这种方法有缺点:使用计时器和调整内容的 margin-top 出现延迟。幸运...
    编程 发布于2024-11-05
  • 从零到 Web 开发人员:掌握 PHP 基础知识
    从零到 Web 开发人员:掌握 PHP 基础知识
    掌握PHP基础知识至关重要:安装PHP创建PHP文件运行代码理解变量和数据类型使用表达式和运算符创建实际项目以提高技能PHP开发入门:掌握PHP基础PHP是一种用途广泛、功能强大的脚本语言,用于创建动态且交互式Web应用程序。对于初学者来说,掌握PHP的基本知识至关重要。一、安装PHP在本地开发机器...
    编程 发布于2024-11-05
  • 缓冲区:Node.js
    缓冲区:Node.js
    Node.js 中缓冲区的简单指南 Node.js 中的 Buffer 用于处理原始二进制数据,这在处理流、文件或网络数据时非常有用。 如何创建缓冲区 来自字符串: const buf = Buffer.from('Hello'); 分配特定大小的Buffer...
    编程 发布于2024-11-05
  • 掌握 Node.js 中的版本管理
    掌握 Node.js 中的版本管理
    作为开发者,我们经常遇到需要不同 Node.js 版本的项目。对于可能不经常参与 Node.js 项目的新手和经验丰富的开发人员来说,这种情况都是一个陷阱:确保每个项目使用正确的 Node.js 版本。 在安装依赖项并运行项目之前,验证您的 Node.js 版本是否匹配或至少兼容项目的要求至关重要。...
    编程 发布于2024-11-05
  • 如何在 Go 二进制文件中嵌入 Git 修订信息以进行故障排除?
    如何在 Go 二进制文件中嵌入 Git 修订信息以进行故障排除?
    确定 Go 二进制文件中的 Git 修订版部署代码时,将二进制文件与构建它们的 git 修订版关联起来会很有帮助排除故障的目的。然而,直接使用修订号更新源代码是不可行的,因为它会改变源代码。解决方案:利用构建标志解决此挑战的方法包括利用构建标志。通过使用构建标志在主包中设置当前 git 修订版的版本...
    编程 发布于2024-11-05
  • 常见 HTML 标签:视角
    常见 HTML 标签:视角
    HTML(超文本标记语言)构成了 Web 开发的基础,是互联网上每个网页的结构。通过了解最常见的 HTML 标签及其高级用途,到 2024 年,开发人员可以创建更高效​​、更易于访问且更具视觉吸引力的网页。在这篇文章中,我们将探讨这些 HTML 标签及其最高级的用例,以帮助您提高 Web 开发技能。...
    编程 发布于2024-11-05
  • CSS 媒体查询
    CSS 媒体查询
    确保网站在各种设备上无缝运行比以往任何时候都更加重要。随着用户通过台式机、笔记本电脑、平板电脑和智能手机访问网站,响应式设计已成为必要。响应式设计的核心在于媒体查询,这是一项强大的 CSS 功能,允许开发人员根据用户设备的特征应用不同的样式。在本文中,我们将探讨什么是媒体查询、它们如何工作以及实现它...
    编程 发布于2024-11-05
  • 了解 JavaScript 中的提升:综合指南
    了解 JavaScript 中的提升:综合指南
    JavaScript 中的提升 提升是一种行为,其中变量和函数声明在之前被移动(或“提升”)到其包含范围(全局范围或函数范围)的顶部代码被执行。这意味着您可以在代码中实际声明变量和函数之前使用它们。 变量提升 变量 用 var 声明的变量被提升到其作...
    编程 发布于2024-11-05
  • 将 Stripe 集成到单一产品 Django Python 商店中
    将 Stripe 集成到单一产品 Django Python 商店中
    In the first part of this series, we created a Django online shop with htmx. In this second part, we'll handle orders using Stripe. What We'll...
    编程 发布于2024-11-05
  • 在 Laravel 中测试排队作业的技巧
    在 Laravel 中测试排队作业的技巧
    使用 Laravel 应用程序时,经常会遇到命令需要执行昂贵任务的情况。为了避免阻塞主进程,您可能决定将任务卸载到可以由队列处理的作业。 让我们看一个例子。想象一下命令 app:import-users 需要读取一个大的 CSV 文件并为每个条目创建一个用户。该命令可能如下所示: /* Import...
    编程 发布于2024-11-05
  • 如何创建人类水平的自然语言理解 (NLU) 系统
    如何创建人类水平的自然语言理解 (NLU) 系统
    Scope: Creating an NLU system that fully understands and processes human languages in a wide range of contexts, from conversations to literature. ...
    编程 发布于2024-11-05
  • 如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    如何使用 JSTL 迭代 HashMap 中的 ArrayList?
    使用 JSTL 迭代 HashMap 中的 ArrayList在 Web 开发中,JSTL(JavaServer Pages 标准标记库)提供了一组标记来简化 JSP 中的常见任务( Java 服务器页面)。其中一项任务是迭代数据结构。要迭代 HashMap 及其中包含的 ArrayList,可以使...
    编程 发布于2024-11-05

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

Copyright© 2022 湘ICP备2022001581号-3