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
相关产品推荐
相关产品推荐

