React问题:点击Column1旁展开面板无法显示Column3内容
React新手问题:点击按钮无法显示Column3条目
我是React新手,预期点击Column1标题旁的「open panel」按钮时,可显示Column3的条目。已使用useState进行状态管理,但功能仍无法正常运行,调试后也未解决问题。
问题代码中的核心问题
- 重复的Droppable ID:代码中创建了两个
droppableId="column3"的组件,react-beautiful-dnd要求每个Droppable的ID必须唯一,这会导致渲染和拖拽逻辑冲突。 - Draggable嵌套错误:面板内的Draggable组件错误嵌套了完整的Droppable结构,还重复渲染了Column3内容,同时错误传递了
provided.droppableProps(这是Droppable组件的专属props,不能用于Draggable)。 - 面板渲染逻辑混乱:面板的触发逻辑与重复的Droppable组件绑定,导致状态切换时无法正确渲染目标内容。
- 状态更新问题:跨列移动时直接修改原状态对象的数组,没有创建深拷贝,导致React无法检测到状态变化,界面不更新。
修复后的代码
import { useState } from 'react'; import './App.css'; import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; function App() { const [panelOpen, setPanelOpen] = useState(false); const [columns, setColumns] = useState({ column1: { id: 'column1', items: ['Sample_Step1', 'Sample_Step2'] }, column2: { id: 'column2', items: [] }, column3: { id: 'column3', items: ['Sample_Step6', 'Sample_Step7'] }, }); const handleDragEnd = (result) => { const { source, destination } = result; if (!destination) return; // 同列重排逻辑 if (source.droppableId === destination.droppableId) { const column = columns[source.droppableId]; const copiedItems = [...column.items]; const [removed] = copiedItems.splice(source.index, 1); copiedItems.splice(destination.index, 0, removed); setColumns({ ...columns, [source.droppableId]: { ...column, items: copiedItems }, }); } else { // 跨列移动逻辑(修复状态更新问题) const sourceColumn = { ...columns[source.droppableId], items: [...columns[source.droppableId].items] }; const destColumn = { ...columns[destination.droppableId], items: [...columns[destination.droppableId].items] }; const [removed] = sourceColumn.items.splice(source.index, 1); destColumn.items.splice(destination.index, 0, removed); setColumns({ ...columns, [source.droppableId]: sourceColumn, [destination.droppableId]: destColumn, }); } }; return ( <div> <DragDropContext onDragEnd={handleDragEnd}> <div style={{ display: 'flex', gap: '20px', padding: '20px' }}> <Droppable droppableId="column1"> {(provided) => ( <div {...provided.droppableProps} ref={provided.innerRef} style={{ minWidth: '200px' }} > <h5> column 1 header{' '} <span onClick={() => setPanelOpen(!panelOpen)} style={{ cursor: 'pointer', color: '#165DFF', textDecoration: 'underline', marginLeft: '8px' }} > open panel </span> </h5> {columns.column1.items.map((item, index) => ( <Draggable key={item} draggableId={item} index={index}> {(provided) => ( <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} style={{ padding: '8px', border: '1px solid #E5E6EB', borderRadius: '4px', margin: '4px 0', backgroundColor: '#FFF' }} > <p>{item}</p> </div> )} </Draggable> ))} {provided.placeholder} </div> )} </Droppable> <Droppable droppableId="column2"> {(provided) => ( <div {...provided.droppableProps} ref={provided.innerRef} style={{ minWidth: '200px' }} > <h5>column 2 header</h5> {columns.column2.items.map((item, index) => ( <Draggable key={item} draggableId={item} index={index}> {(provided) => ( <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} style={{ padding: '8px', border: '1px solid #E5E6EB', borderRadius: '4px', margin: '4px 0', backgroundColor: '#FFF' }} > <p>{item}</p> </div> )} </Draggable> ))} {provided.placeholder} </div> )} </Droppable> <Droppable droppableId="column3"> {(provided) => ( <div {...provided.droppableProps} ref={provided.innerRef} style={{ minWidth: '200px' }} > <h5>column 3 header</h5> {columns.column3.items.map((item, index) => ( <Draggable key={item} draggableId={item} index={index}> {(provided) => ( <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} style={{ padding: '8px', border: '1px solid #E5E6EB', borderRadius: '4px', margin: '4px 0', backgroundColor: '#FFF' }} > <p>{item}</p> </div> )} </Draggable> ))} {provided.placeholder} </div> )} </Droppable> {/* 折叠面板:点击按钮后显示Column3条目 */} {panelOpen && ( <div className="vertical-panel" style={{ minWidth: '200px', border: '1px solid #E5E6EB', borderRadius: '4px', padding: '10px', marginTop: '24px', backgroundColor: '#F7F8FA' }} > <h5>column 3 面板</h5> {columns.column3.items.map((item, index) => ( <Draggable key={item} draggableId={item} index={index}> {(provided) => ( <div {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} style={{ padding: '8px', border: '1px solid #E5E6EB', borderRadius: '4px', margin: '4px 0', backgroundColor: '#FFF' }} > <p>{item}</p> </div> )} </Draggable> ))} </div> )} </div> </DragDropContext> </div> ); } export default App;
修复说明
- 删除重复Droppable:移除了第二个
droppableId="column3"组件,确保每个拖拽容器ID唯一。 - 重构面板逻辑:将折叠面板独立出来,通过
panelOpen状态直接控制显示/隐藏,不再嵌套错误的拖拽结构。 - 修复状态更新:跨列移动时对列对象和数组进行深拷贝,确保React能检测到状态变化,触发界面更新。
- 优化交互体验:给按钮添加了样式提示,给拖拽项增加了基础样式,提升界面可读性。
内容的提问来源于stack exchange,提问作者Ram01
相关产品推荐
相关产品推荐

