You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中DnD-Kit跨容器拖拽任务卡片异常问题求助

问题排查与修复方案

针对你遇到的跨列拖拽无响应、偶尔报错Uncaught TypeError: Cannot read properties of undefined (reading 'id')的问题,以下是具体问题点和修复方案:


1. 拖拽结束时未判断over对象是否存在

报错的直接原因是:当拖拽到列的空白区域时,over对象可能为undefined,直接访问over.data.current.sortable会抛出属性读取错误。

修复代码:

const handleDragEnd = ({active, over}) => {
    // 先判断over是否存在,不存在直接结束
    if (!over) {
        setActiveId(null);
        return;
    }

    const { containerId: activeContainer } = active.data.current.sortable
    const { containerId: overContainer } = over.data.current.sortable
    // ... 后续逻辑
}

2. 跨列拖拽的数组更新逻辑错误

当前用arrayMove处理目标列数组,但arrayMove仅适合同数组内元素移动。跨列拖拽需要将任务从原列移除,再插入到目标列的对应位置,而非修改目标列原有元素顺序。

修复代码:

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

    const { containerId: activeContainer } = active.data.current.sortable
    const { containerId: overContainer } = over.data.current.sortable
    const activeTaskId = active.id;

    // 同列拖拽:仅调整当前列内元素顺序
    if (activeContainer === overContainer) {
        const oldIndex = tasks[activeContainer].findIndex(obj => obj.id === activeTaskId);
        const newIndex = tasks[overContainer].findIndex(obj => obj.id === over.id);
        if (oldIndex !== newIndex) {
            setTasks(prev => ({
                ...prev,
                [activeContainer]: arrayMove(prev[activeContainer], oldIndex, newIndex)
            }));
        }
    } 
    // 跨列拖拽:移动任务到目标列,同时删除原列的任务
    else {
        const movedTask = tasks[activeContainer].find(task => task.id === activeTaskId);
        // 原列删除任务
        const updatedActiveColumn = tasks[activeContainer].filter(task => task.id !== activeTaskId);
        // 目标列插入任务(拖拽到空白区域则插入到末尾)
        const insertIndex = tasks[overContainer].findIndex(obj => obj.id === over.id);
        const updatedOverColumn = [...tasks[overContainer]];
        insertIndex === -1 ? updatedOverColumn.push(movedTask) : updatedOverColumn.splice(insertIndex, 0, movedTask);
        
        setTasks(prev => ({
            ...prev,
            [activeContainer]: updatedActiveColumn,
            [overContainer]: updatedOverColumn
        }));
    }

    setActiveId(null);
}

3. SortableContext的items属性传入错误

SortableContext要求items传入可拖拽元素的id数组,但当前传入的是完整任务对象数组,导致dnd-kit无法正确识别可拖拽项,这是跨列拖拽无响应的核心原因之一。

修复代码(修改TasksColumn.js):

<SortableContext items={tasks.map(task => task.id)} id={id} strategy={verticalListSortingStrategy}>
    <div ref={setNodeRef} className=''>  
       {tasks.map(task => (
            <Draggable key={task.id} id={task.id} task={task} />
        ))} 
    </div>            
</SortableContext>  

4. Draggable组件的key值不唯一

当前用task.name作为key,若存在同名任务会导致key重复,引发React渲染异常,干扰拖拽逻辑。

修复代码(修改TasksColumn.js中Draggable的key):

<Draggable key={task.id} id={task.id} task={task} />

5. 重复使用useSortable导致冲突

Draggable组件已调用useSortable,TaskCard中再次调用会导致同一个元素绑定多个拖拽实例,引发逻辑冲突。

修复代码:

  1. 修改Draggable.js,将激活器逻辑移到此处:
const Draggable = ({ id, task }) => {
    const { setNodeRef, transform, transition, isDragging, attributes, listeners, setActivatorNodeRef } = useSortable({id});

    const style = {
        transform: CSS.Translate.toString(transform),
        transition,
        opacity: isDragging ? 0.5 : 1,
    };

  return (
    <div ref={setNodeRef} style={style}>
        <TaskCard id={id} task={task} attributes={attributes} listeners={listeners} setActivatorNodeRef={setActivatorNodeRef} />
    </div>
  )
}
  1. 修改TaskCard.js,移除内部的useSortable调用:
const TaskCard = ({ id, task, attributes, listeners, setActivatorNodeRef }) => {
    return (
        <div className="py-4 border-b-2 border-grayLight">
            <div className="">
                <p className="">{task.deadline}</p>
                <p className="">{task.priority}</p>
            </div>
            <ArrowsPointingOutIcon className='rotate-45 w-5 h-5 outline-none' ref={setActivatorNodeRef} {...listeners} {...attributes} />
            <p className="">{task.name}</p>
            <div className="">
                <p className="">{task.author}</p>
                <p className="">{task.time}</p>
            </div>
        </div>  
    )
}

内容的提问来源于stack exchange,提问作者rey2197

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 16:20:29