React中react-beautiful-dnd拖拽失效:ButtonBeginningPages拖动后复位
问题原因
你的代码里Draggable组件的index是硬编码的固定值,且没有在拖拽结束后更新页面列表的数据源顺序。react-beautiful-dnd仅负责拖拽的UI交互,真正的列表顺序变更需要手动更新状态/数据源,否则组件会因数据源未变化,重新渲染时回到原始位置。
修复步骤
1. 定义可维护的起始页面数据源
把硬写的起始页面改成数组形式,作为组件状态(若需全局维护可从props传入):
// 在组件内部初始化状态 const [beginningPages, setBeginningPages] = React.useState([ { id: 'frontCover', text: 'Front Cover', screenType: 'coverPage' }, { id: 'titlePage', text: 'Title Page', screenType: 'titlePage' }, { id: 'dedicationPage', text: 'Dedication', screenType: 'dedicationPage' }, { id: 'introductionPage', text: 'Introduction', screenType: 'introductionPage' }, { id: 'tocPage', text: 'Table of Contents', screenType: 'tocPage' }, ]);
2. 添加拖拽结束的处理逻辑
给DragDropContext绑定onDragEnd函数,处理拖拽后的顺序更新:
const handleDragEnd = (result) => { // 拖拽取消时直接返回 if (!result.destination) return; // 拖拽到原位置时无需更新 if (result.source.index === result.destination.index) return; // 复制原数组,避免直接修改状态 const newPages = Array.from(beginningPages); // 取出被拖拽项并插入到目标位置 const [movedItem] = newPages.splice(result.source.index, 1); newPages.splice(result.destination.index, 0, movedItem); // 更新状态 setBeginningPages(newPages); };
修改DragDropContext的调用:
<DragDropContext onDragEnd={handleDragEnd}>
3. 动态渲染Draggable组件
将硬写的5个Draggable改为循环渲染,根据beginningPages数组的顺序生成:
<AccordionBox text="Beginning Pages" isOpen={beginningPagesIsOpen} toggle={toggleBeginningNav} rightCta={<div className={css.tooltip}><Tooltip /></div>} > {beginningPages.map((page, index) => ( <Draggable key={page.id} draggableId={page.id} index={index}> {(provided) => ( <div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} > <ButtonBeginningPages text={page.text} icon={ page.screenType === 'coverPage' && coverPageIsUpdating ? <Spinner size="small" /> : page.screenType === 'titlePage' && titlePageIsUpdating ? <Spinner size="small" /> : page.screenType === 'dedicationPage' && dedicationPageIsUpdating ? <Spinner size="small" /> : page.screenType === 'introductionPage' && introductionPageIsUpdating ? <Spinner size="small" /> : null } active={ page.screenType === 'introductionPage' ? displayedScreen === 'introductionPage' || displayedScreen === 'introductionSubpage' : displayedScreen === page.screenType } canEditPage={!isContributor} onClick={() => { updateCurrentPage({ type: page.screenType }) }} /> </div> )} </Draggable> ))} </AccordionBox>
额外注意事项
- 若页面顺序需要全局同步(比如和后端交互),需将
beginningPages状态提升到父组件或使用状态管理工具,并在handleDragEnd中调用对应的更新接口。 - 确保
draggableId唯一且稳定,不能随索引变化,这里使用页面的id即可满足要求。
内容的提问来源于stack exchange,提问作者yerick
相关产品推荐
相关产品推荐

