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

基于react-beautiful-dnd实现类别拖拽及跨类别拖拽项更新

解决方案

一、实现类别拖拽排序

要让静态类别支持拖拽排序,需完成以下操作:

  1. 将categories转为React状态
    把原来的静态类别数组改为状态变量,方便拖拽后更新排序:
const [categories, setCategories] = useState([
  // 替换为你的初始类别数据,示例:{ id: 1, name: "待办" }, { id: 2, name: "已完成" }
]);
  1. 重构DragDropContext结构
    在外层新增顶级Droppable容器承载所有可拖拽类别,每个类别用Draggable包裹,同时保留类别内部存放items的Droppable:
<DragDropContext onDragEnd={handleDragEnd}>
  {/* 顶级类别容器,支持垂直拖拽排序 */}
  <Droppable droppableId="category-list" direction="vertical">
    {(categoryContainerProvided) => (
      <div 
        ref={categoryContainerProvided.innerRef}
        {...categoryContainerProvided.droppableProps}
      >
        {categories.map((category, idx) => (
          {/* 每个类别作为可拖拽项 */}
          <Draggable
            key={category.id}
            draggableId={category.id.toString()}
            index={idx}
            type="category" // 标记拖拽类型,区分item拖拽
          >
            {(categoryProvided) => (
              <div
                ref={categoryProvided.innerRef}
                {...categoryProvided.draggableProps}
                {...categoryProvided.dragHandleProps}
                style={{ margin: "10px 0", padding: "10px", border: "1px solid #eee" }} // 可选:添加样式方便拖拽识别
              >
                {/* 原有类别内部的item容器 */}
                <Droppable droppableId={category.id.toString()}>
                  {(itemContainerProvided) => (
                    <div 
                      ref={itemContainerProvided.innerRef}
                      {...itemContainerProvided.droppableProps}
                    >
                      <Category
                        category={category}
                        items={items}
                        provided={itemContainerProvided}
                      />
                      {itemContainerProvided.placeholder}
                    </div>
                  )}
                </Droppable>
              </div>
            )}
          </Draggable>
        ))}
        {categoryContainerProvided.placeholder}
      </div>
    )}
  </Droppable>
</DragDropContext>
  1. 更新拖拽结束逻辑,处理类别排序
    在handleDragEnd中先判断拖拽类型,单独处理类别排序:
const handleDragEnd = (result) => {
  const { source, destination, type } = result;

  // 无有效目标时直接返回
  if (!destination) return;

  // 处理类别拖拽排序
  if (type === "category") {
    // 拖拽位置未变化时无需更新
    if (source.index === destination.index) return;

    const updatedCategories = [...categories];
    const [movedCategory] = updatedCategories.splice(source.index, 1);
    updatedCategories.splice(destination.index, 0, movedCategory);
    setCategories(updatedCategories);
    return;
  }

  // 原有item拖拽逻辑保持不变
  if (destination.droppableId !== source.droppableId) {
    setItems(prevItems => 
      prevItems.map(item => 
        item.id === parseInt(result.draggableId)
          ? { ...item, category: parseInt(destination.droppableId) }
          : item
      )
    );
  } else {
    const itemsCopy = [...items];
    const [removed] = itemsCopy.splice(source.index, 1);
    itemsCopy.splice(destination.index, 0, removed);
    setItems(itemsCopy);
  }
};

二、确保跨类别拖拽时同步更新item.category

你当前的代码已实现该功能,可优化代码可读性并确保使用prevState避免状态更新竞态:

// 跨类别拖拽时的逻辑片段
if (destination.droppableId !== source.droppableId) {
  setItems(prevItems => 
    prevItems.map(item => {
      if (item.id === parseInt(result.draggableId)) {
        return {
          ...item,
          category: parseInt(destination.droppableId)
        };
      }
      return item;
    })
  );
}

这段代码基于上一次的items状态更新,保证数据与UI一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:01:03