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

dnd-kit中useSortable钩子使用报错与正确用法咨询

报错根本原因

你的代码报错核心是**SortableContext注册的可排序项ID和子组件useSortable传入的ID完全不匹配**,具体错误点如下:

  • 你的数据源data只有id、text两个字段,不存在name字段,但传给SortableContext的items属性写的是data.map((i) => i.name),实际传入的是全为undefined的无效数组。
  • 子组件Cards里调用useSortable时传入的id是数据项的id值("1"~"5"),这些id根本不在上面的无效items数组里,dnd-kit内部校验不通过,就会抛出类似「useSortable必须在SortableContext内调用」的误导性报错。
  • 拖拽结束逻辑handleDragEnd里同样用不存在的i.name匹配拖拽id,永远拿不到正确的元素索引,会得到-1传入arrayMove,直接导致排序逻辑异常。
修正后的可运行代码

Home 组件修正

import React, { useState } from "react";
import "./Home.css";
import Cards from "../../components/cards/Cards";
import { Container } from "./HomeStyles";
import {
  DndContext,
  closestCorners,
  MouseSensor,
  TouchSensor,
  useSensor,
  useSensors
} from "@dnd-kit/core";
import {
  arrayMove,
  SortableContext,
  rectSortingStrategy
} from "@dnd-kit/sortable";

const Home = () => {
  const sensors = useSensors(useSensor(MouseSensor), useSensor(TouchSensor));

  const [data, setData] = useState([
    { id: "1", text: "H" },
    { id: "2", text: "E" },
    { id: "3", text: "L" },
    { id: "4", text: "L" },
    { id: "5", text: "O" },
  ]);

  function handleDragEnd(event) {
    const { active, over } = event;
    if (active.id !== over.id) {
      setData((items) => {
        // 用数据里真实存在的id字段匹配索引
        const oldIndex = items.findIndex((i) => i.id === active.id);
        const newIndex = items.findIndex((i) => i.id === over.id);
        return arrayMove(items, oldIndex, newIndex);
      });
    }
  }

  return (
    <Container>
      <DndContext
        autoScroll={false}
        sensors={sensors}
        collisionDetection={closestCorners}
        onDragEnd={handleDragEnd}
      >
        <SortableContext
          // 传入和useSortable一致的唯一id列表
          items={data.map((i) => i.id)}
          strategy={rectSortingStrategy}
        >
          <div
            style={{
              height: "100%",
              width: "100%",
              maxHeight: "30rem",
              maxWidth: "40rem",
              display: "flex",
              flexDirection: "column",
              flexWrap: "wrap"
            }}
          >
            {data.map((item) => (
              <Cards key={item.id} id={item.id} name={item.text} />
            ))}
          </div>
        </SortableContext>
      </DndContext>
    </Container>
  );
};

export default Home;

Cards 组件修正(规范命名,无逻辑错误)

import React from "react";
import { Card } from "./CardsStyled";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";

// 组件名首字母大写符合React规范,props语义化命名
const Cards = ({ id, name }) => {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition
  } = useSortable({ id });

  const style = {
    transition,
    transform: CSS.Transform.toString(transform),
    border: "2px solid black",
    marginBottom: 5,
    marginTop: 5,
  };

  return (
    <div>
      <Card ref={setNodeRef} {...attributes} {...listeners} style={style}>
        <h1>{name}</h1>
      </Card>
    </div>
  );
};

export default Cards;
useSortable 标准用法规范
  • useSortable必须在SortableContext包裹的子组件树内调用,不能在Context外层使用。
  • 每个调用useSortable的组件传入的id必须全局唯一,且必须存在于父级SortableContext的items数组中,两者要严格对应,这是最容易踩坑的点。
  • SortableContext的items数组必须是所有可排序项的唯一ID列表,默认顺序要和页面渲染顺序一致,排序时只需要更新这个数组的顺序即可。
  • 拖拽回调中查找索引时,必须用和useSortable一致的唯一id做匹配,不要用不存在或者不唯一的字段匹配。
  • 可排序组件定义时首字母要大写,符合React JSX的组件解析规则,避免和原生HTML标签混淆。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:27:27