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

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']这种写法完全不符合数组的访问规则。

修复步骤

  1. 存储数组索引而非列名:拖拽事件直接传递数组的index,而不是通过DOM元素的id获取字符串
  2. 修正useRef类型:不用any,指定为number | null,解决类型报错同时保证类型安全
  3. 完善拖拽事件逻辑:添加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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 16:15:07