React原生拖拽中dragItemContent返回undefined问题求助
原生拖拽表格列问题:dragItemContent返回undefined排查
我尝试创建一个两列表格,其中一列用原生拖拽实现排序功能。当前核心问题是代码const dragItemContent = copyListItems[dragItem.current];中的dragItemContent返回undefined,无法确定原因,恳请协助排查。
完整代码参考
import { useState, useRef } from 'react'; import { Container, Table } from 'react-bootstrap'; const DragTable = () => { const standardNames = ['Tests 1', 'Tests 2', 'Tests 3', 'Tests 4', 'Tests 5']; const [columnNames, setData] = useState([ 'Test 5', 'Test 3', 'Test 2', 'Test 4', 'Test 1' ]); const dragItem = useRef<any>(); const dragOverItem = useRef<any>(); const dragStart = (e: any) => { dragItem.current = e.target.id; console.log(e.target.innerHTML); }; const dragEnter = (e: any) => { dragOverItem.current = e.currentTarget.id; console.log(e.currentTarget.innerHTML); } const drop = () => { const copyListItems = [...columnNames]; const dragItemContent = copyListItems[dragItem.current]; copyListItems.splice(dragItem.current, 1); copyListItems.splice(dragOverItem.current, 0, dragItemContent); dragItem.current = null; dragOverItem.current = null; setData(copyListItems); } return ( <Container /*style={cancellationContainerStyle}*/> <Table className="mt-3" style={{ backgroundColor: 'white' }} bordered hover> <thead> <tr style={{ backgroundColor: 'white' }}> <th className="styleCancellationsColHeader" style={{ backgroundColor: 'white' }}>Standard Template Names</th> <th className="styleCancellationsColHeader" style={{ backgroundColor: 'white' }}>Excel Column Names</th> </tr> </thead> <tbody> {standardNames.map((standardName: string, index) => ( <tr> <td> {standardNames[index]} </td> <td draggable onDragStart={(e) => dragStart(e)} onDragEnter={(e) => dragEnter(e)} onDragEnd={drop} key={columnNames[index]} id={columnNames[index]} > {columnNames[index]} </td> </tr> ))} </tbody> </Table> </Container> ) } export default DragTable;
另外,我必须给useRef指定any类型,否则会报错:Type 'undefined' cannot be used as an index type (property) React.MutableRefObject<undefined>.current: undefined
问题根源与解决方案
核心问题:用字符串作为数组索引
你把列内容(比如Test 5)作为id存在dragItem.current里,但数组的索引是数字类型,用字符串去访问数组元素自然会返回undefined。比如copyListItems['Test 5']这种写法完全不符合数组的访问规则。
修复步骤
- 存储数组索引而非列名:拖拽事件直接传递数组的index,而不是通过DOM元素的id获取字符串
- 修正useRef类型:不用any,指定为
number | null,解决类型报错同时保证类型安全 - 完善拖拽事件逻辑:添加
onDragOver并阻止默认行为,这是触发drop事件的必要条件;将onDragEnd替换为onDrop,符合原生拖拽的触发逻辑
修改后的完整代码
import { useState, useRef } from 'react'; import { Container, Table } from 'react-bootstrap'; const DragTable = () => { const standardNames = ['Tests 1', 'Tests 2', 'Tests 3', 'Tests 4', 'Tests 5']; const [columnNames, setData] = useState([ 'Test 5', 'Test 3', 'Test 2', 'Test 4', 'Test 1' ]); // 指定类型为number或null,替代any const dragItem = useRef<number | null>(null); const dragOverItem = useRef<number | null>(null); // 直接接收index参数,无需从DOM元素获取id const dragStart = (index: number) => { dragItem.current = index; }; const dragEnter = (index: number) => { dragOverItem.current = index; }; // 必须阻止默认行为,否则drop事件不会触发 const dragOver = (e: React.DragEvent) => { e.preventDefault(); }; const drop = () => { // 先判断是否有效索引 if (dragItem.current === null || dragOverItem.current === null) return; const copyListItems = [...columnNames]; // 用数字索引获取元素,正确访问数组 const dragItemContent = copyListItems[dragItem.current]; copyListItems.splice(dragItem.current, 1); copyListItems.splice(dragOverItem.current, 0, dragItemContent); dragItem.current = null; dragOverItem.current = null; setData(copyListItems); }; return ( <Container> <Table className="mt-3" style={{ backgroundColor: 'white' }} bordered hover> <thead> <tr style={{ backgroundColor: 'white' }}> <th className="styleCancellationsColHeader" style={{ backgroundColor: 'white' }}>Standard Template Names</th> <th className="styleCancellationsColHeader" style={{ backgroundColor: 'white' }}>Excel Column Names</th> </tr> </thead> <tbody> {standardNames.map((_standardName, index) => ( <tr key={index}> <td> {standardNames[index]} </td> <td draggable onDragStart={() => dragStart(index)} onDragEnter={() => dragEnter(index)} onDragOver={dragOver} onDrop={drop} id={`column-${index}`} > {columnNames[index]} </td> </tr> ))} </tbody> </Table> </Container> ); }; export default DragTable;
额外说明
- 去掉了
any类型后,通过给useRef指定number | null,既解决了类型报错,又能在代码里做空值判断,避免潜在的运行时错误 - 原生拖拽中,
onDragOver必须阻止默认行为,否则浏览器会认为该区域不可放置,drop事件不会触发 - 用
index作为tr的key更合理,因为columnNames是动态变化的,用列名做key可能导致React渲染异常
内容的提问来源于stack exchange,提问作者NomadsThings
相关产品推荐
相关产品推荐

