React拖拽功能报错:Cannot read properties of undefined reading 'indexOf'求助
问题排查与修复
核心错误原因
- 笔误导致属性未找到:
drop函数里的currentBoard.item.indexOf(currentItem)是拼写错误,应该是currentBoard.items(复数形式),少了s导致访问undefined的indexOf方法,触发报错。 - 直接修改State对象:使用
splice直接修改currentBoard.items和board.items,违反React状态不可变原则,会导致状态更新异常。 - 未处理初始空状态:
currentBoard初始值为null,若在未拖拽时触发drop,访问currentBoard.items会报错。 - 缺少key属性:组件循环渲染时未添加唯一
key,会触发keys相关警告。
修复后的完整代码
import { useState } from 'react'; const App = () => { const [boards, setBoards] = useState([ {id: 1, title: "Не начато", items: [{id: 1, title:"a"}, {id:2, title:"b"}, {id:3, title:"c"}] } ]) const [currentBoard, setCurrentBoard] = useState(null) const [currentItem, setCurrentItem] = useState(null) function dOH (e){ e.preventDefault() } function dLH (e){} function dSH (e, board, item){ setCurrentBoard(board) setCurrentItem(item) } function dEH (e){} function drop(e, targetBoard, targetItem) { e.preventDefault() // 避免未拖拽时触发drop导致的空值错误 if (!currentBoard || !currentItem) return; // 创建原数组副本,避免直接修改state const sourceItems = [...currentBoard.items]; const currentIndex = sourceItems.indexOf(currentItem); if (currentIndex === -1) return; // 未找到元素时直接返回 sourceItems.splice(currentIndex, 1); const targetItems = [...targetBoard.items]; const dropIndex = targetItems.indexOf(targetItem); targetItems.splice(dropIndex + 1, 0, currentItem); // 更新boards状态,创建新对象避免直接修改原state setBoards(prevBoards => prevBoards.map(b => { if(b.id === targetBoard.id){ return {...b, items: targetItems}; } if(b.id === currentBoard.id){ return {...b, items: sourceItems}; } return b; })) // 重置当前拖拽状态 setCurrentBoard(null); setCurrentItem(null); } return ( <div> {boards.map (board => <div key={board.id}> <div>{board.title}</div> {board.items.map (item => <div key={item.id} onDragOver={(e) => dOH(e)} onDragLeave={(e) => dLH(e)} onDragStart={(e) => dSH(e, board, item)} onDragEnd={(e) => dEH(e)} onDrop={(e) => drop(e, board, item)} draggable={true} > {item.title} </div> )} </div> )} </div> ) } export default App
关键修改说明
- 修正了
currentBoard.item的拼写错误,改为currentBoard.items。 - 对数组使用扩展运算符
[...arr]创建副本,再进行splice操作,遵循状态不可变原则。 - 在
drop函数开头添加空值判断,避免未拖拽时的报错。 - 给
map循环的元素添加了key属性,使用board.id和item.id作为唯一标识。 - 更新
boards时使用函数式更新prevBoards,确保获取最新的状态值。 - 拖拽完成后重置
currentBoard和currentItem,避免重复触发异常。
内容的提问来源于stack exchange,提问作者blatt
相关产品推荐
相关产品推荐

