React实现Drag and Drop报dispatch属性无效且拖拽失效问题
问题定位与修正方案
1. 控制台报错的直接原因
你把data、dispatch直接绑定在<Jumbotron>标签上是触发警告的核心原因。react-bootstrap的Jumbotron最终会渲染成真实的HTML DOM节点,只有字符串、数字类型的原生HTML属性才会被保留在DOM上;函数、对象这类非基础类型的值传给DOM节点时,React就会抛出「属性值无效,请移除属性或传入字符串/数字」的报错。
- 你的拖拽事件处理函数本身和
data、dispatch在同一个函数作用域下,根本不需要通过props往DOM上透传这两个变量,直接把Jumbotron标签上的data={data} dispatch={dispatch}删掉,警告就会消失。
2. 拖拽功能失效的缺失逻辑
就算移除报错的属性,当前的拖拽逻辑也无法正常工作,存在几个关键疏漏:
- 状态判断逻辑错误:
handleDragLeave里用闭包捕获的旧data值判断dropDepth是否大于0,而dispatch是异步更新的,闭包里拿到的永远是触发事件时的旧状态,会导致拖拽区内的状态判断错乱。应该用计算得出的新dropDepth值做判断,不要依赖旧的闭包状态。 - 核心文件读取逻辑缺失:当前的
handleDrop只做了阻止浏览器默认行为,没有从拖拽事件的dataTransfer对象里取出拖入的文件,也没有触发ADD_FILE_TO_LIST的状态更新动作,就算拖拽动作触发了,文件也不会被存入你的状态列表。 - 拖拽状态的边界处理不完整:没有在拖拽进入、离开、放下的各个节点重置
dropDepth和inDropZone的状态,会导致多次拖拽后状态计数错乱。
关键代码修正示例
// 拖拽进入事件 const handleDragEnter = e => { e.preventDefault(); e.stopPropagation(); e.dataTransfer.dropEffect = 'copy'; dispatch({ type: 'SET_DROP_DEPTH', dropDepth: data.dropDepth + 1 }); }; // 拖拽离开事件 const handleDragLeave = e => { e.preventDefault(); e.stopPropagation(); const newDepth = data.dropDepth - 1; dispatch({ type: 'SET_DROP_DEPTH', dropDepth: newDepth }); // 用计算出的新深度判断状态,不依赖闭包的旧值 if (newDepth <= 0) { dispatch({ type: 'SET_IN_DROP_ZONE', inDropZone: false }) } }; // 拖拽在区域内移动事件 const handleDragOver = e => { e.preventDefault(); e.stopPropagation(); e.dataTransfer.dropEffect = 'copy'; }; // 拖拽放下事件 const handleDrop = e => { e.preventDefault(); e.stopPropagation(); // 取出所有拖入的文件 const droppedFiles = Array.from(e.dataTransfer.files); // 重置拖拽悬浮状态 dispatch({ type: 'SET_DROP_DEPTH', dropDepth: 0 }); dispatch({ type: 'SET_IN_DROP_ZONE', inDropZone: false }); // 把文件存入状态 if (droppedFiles.length) { dispatch({ type: 'ADD_FILE_TO_LIST', files: droppedFiles }); } };
修正后的Jumbotron标签,移除多余的非DOM属性:
<Jumbotron className="jumbotronSurvey" onDrop={e => handleDrop(e)} onDragOver={e => handleDragOver(e)} onDragEnter={e => handleDragEnter(e)} onDragLeave={e => handleDragLeave(e)} >
内容的提问来源于stack exchange,提问作者Ajay Kulkarni
相关产品推荐
相关产品推荐

