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

React Dnd-kit拖拽动画异常:拖拽元素回退至原位置而非目标插槽

修复React DnD Kit放置后元素回退到起始位置的问题

核心问题诊断

你的代码存在两个关键问题导致动画异常:

  1. 拖拽结束后未将元素最终位置(目标插槽坐标)同步到组件状态,组件重渲染时元素会回到初始位置
  2. Draggable组件的位置计算未与目标插槽坐标绑定,动画系统无法识别正确的目标落点

具体修复步骤

1. 维护元素位置状态

在App.tsx中为每个拖拽元素添加position状态,记录其当前所在插槽索引:

// App.tsx
import { useState } from 'react';
import DraggableItem from './draggable-item';
import DroppableContainer from './droppable-container';

const initialItems = [
  { id: 'plus', symbol: '+', position: 0 },
  { id: 'minus', symbol: '-', position: 1 },
  { id: 'colon', symbol: ':', position: 2 },
  { id: 'star', symbol: '*', position: 3 },
];

const slotCount = 6;

function App() {
  const [items, setItems] = useState(initialItems);

  const handleDragEnd = (itemId: string, targetSlotIndex: number) => {
    setItems(prevItems => 
      prevItems.map(item => 
        item.id === itemId ? { ...item, position: targetSlotIndex } : item
      )
    );
  };

  return (
    <div className="app">
      <div className="draggable-items">
        {items.map(item => (
          <DraggableItem
            key={item.id}
            id={item.id}
            symbol={item.symbol}
            position={item.position}
          />
        ))}
      </div>

      <DroppableContainer
        slotCount={slotCount}
        items={items}
        onDragEnd={handleDragEnd}
      />
    </div>
  );
}

export default App;

2. 绑定Draggable组件的动画目标位置

在draggable-item.tsx中,将元素位置与拖拽动画系统绑定,确保结束后能平滑过渡到目标插槽:

// draggable-item.tsx
import { useDraggable } from '@dnd-kit/core';
import { CSS } from '@dnd-kit/utilities';

interface DraggableItemProps {
  id: string;
  symbol: string;
  position: number;
}

export default function DraggableItem({ id, symbol, position }: DraggableItemProps) {
  const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({
    id,
    data: { position },
  });

  const style = {
    transform: CSS.Transform.toString(transform),
    opacity: isDragging ? 0.5 : 1,
    order: position, // 适配flex布局的插槽排序
  };

  return (
    <div
      ref={setNodeRef}
      style={style}
      {...attributes}
      {...listeners}
      className="draggable-item"
    >
      {symbol}
    </div>
  );
}

3. 正确处理Droppable容器的放置事件

在droppable-container.tsx中,确保放置时传递正确的目标插槽索引,触发父组件更新元素位置:

// droppable-container.tsx
import { useDroppable } from '@dnd-kit/core';
import Item from './item';

interface DroppableContainerProps {
  slotCount: number;
  items: Array<{ id: string; symbol: string; position: number }>;
  onDragEnd: (itemId: string, targetSlotIndex: number) => void;
}

export default function DroppableContainer({ slotCount, items, onDragEnd }: DroppableContainerProps) {
  return (
    <div className="droppable-container">
      {Array.from({ length: slotCount }).map((_, index) => {
        const { isOver, setNodeRef, active } = useDroppable({
          id: `slot-${index}`,
        });

        const item = items.find(i => i.position === index);

        return (
          <div
            key={`slot-${index}`}
            ref={setNodeRef}
            className={`slot ${isOver ? 'slot-over' : ''}`}
            onMouseUp={() => {
              if (active?.id) {
                onDragEnd(active.id as string, index);
              }
            }}
          >
            {item ? <Item symbol={item.symbol} /> : null}
          </div>
        );
      })}
    </div>
  );
}

4. 配置动画插件(可选补充)

若动画仍不生效,安装并配置@dnd-kit/animation插件:

npm install @dnd-kit/animation

在main.tsx中添加插件:

// main.tsx
import { DndContext, closestCenter } from '@dnd-kit/core';
import { Animation } from '@dnd-kit/animation';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <DndContext
      collisionDetection={closestCenter}
      plugins={[Animation]}
    >
      <App />
    </DndContext>
  </React.StrictMode>,
);

关键注意事项

  • 必须保证拖拽结束后,元素的位置状态被正确更新到组件state,否则重渲染会回到初始位置
  • 拖拽元素的布局属性(如order或绝对定位坐标)要与插槽位置绑定
  • 动画插件需正确配置,否则无法触发平滑过渡效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:03:10