React函数组件实现拖拽时onDragOver无法访问state问题求助
问题根本原因
- 闭包陷阱:React函数组件每次重渲染都会生成新的作用域,绑定的拖拽事件回调捕获的是首次渲染时的
itemsstate和局部变量快照,后续state更新后回调里拿到的还是旧值 - 声明的
draggedItem是普通局部变量,每次组件重渲染都会被重置为null,无法跨渲染周期保存值 - 更新
items时直接用了splice修改原state数组,违反了React不可变数据原则,会导致渲染异常
修复后的完整代码
import { useState, useRef } from 'react'; function MenuCreatorCourse() { const [items, setItems] = useState([1, 2]); // 用useRef存拖拽的元素,跨渲染周期保持值更新 const draggedItemRef = useRef(null); function onDragStart(e, index) { draggedItemRef.current = items[index]; e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/html", e.target.parentNode); e.dataTransfer.setDragImage(e.target.parentNode, 20, 20); console.log("draggedItem @ DragStart", draggedItemRef.current); } const onDragOver = (e, index) => { e.preventDefault(); const draggedOverItem = items[index]; console.log("@onDragOver", index, items); console.log("draggedOverItem", draggedOverItem); // 拖拽到自身直接返回 if (draggedItemRef.current === draggedOverItem) { return; } // 按照不可变原则生成新数组,不要修改原state const newItems = [...items]; // 先删除原位置的拖拽元素 const draggedIndex = newItems.indexOf(draggedItemRef.current); newItems.splice(draggedIndex, 1); // 插入到目标位置 newItems.splice(index, 0, draggedItemRef.current); setItems(newItems); console.log("draggedItem @ DragOver", draggedItemRef.current); }; function onDragEnd() { // 拖拽结束清空ref draggedItemRef.current = null; } return ( <ul onDragOver={(e) => e.preventDefault()}> {items.map((item, idx) => ( <li className={classes.courseinput} key={item} onDragOver={(e) => onDragOver(e, idx)} > <div className="drag" draggable onDragStart={(e) => onDragStart(e, idx)} onDragEnd={onDragEnd} > <DragAndDropIcon /> </div> <div></div> <div className="form-control"> <input type="text" id="description" placeholder="Description" /> </div> <div> <RemoveIcon /> </div> </li> ))} </ul> ); } export default MenuCreatorCourse;
核心修改点
- 用
useRef存储draggedItem,ref的current属性可以跨渲染周期保持最新值,不受闭包影响 - 生成新数组时采用展开运算符复制原数组后再修改,不直接操作原state,符合React数据更新规范
- 补充了
onDragEnd逻辑,拖拽结束后清空存储的拖拽元素,避免后续逻辑异常
内容的提问来源于stack exchange,提问作者user2601660
相关产品推荐
相关产品推荐

