React Final Form结合react-beautiful-dnd拖拽时UI出现重复行问题
React Final Form结合react-beautiful-dnd拖拽时UI出现重复行问题
嗨,我刚好碰到过类似的问题,帮你梳理下可能的原因和解决办法~
你提到的情况很典型:拖拽后状态是正确的,但UI却重复了最后一行,这大多是因为React的渲染机制和两个库的交互逻辑没匹配上,具体来说有这几个关键点:
核心原因分析
- 不稳定的key值:如果列表项用
index作为key,拖拽改变顺序后,React会因为key重复/错乱,误把旧的DOM节点复用成新的行,导致重复渲染。 - 拖拽临时元素干扰:react-beautiful-dnd在拖拽过程中会克隆一个临时的拖拽元素,如果这个元素没有被正确区分,FieldArray可能会把它当成列表的一部分渲染。
- 表单更新时机不匹配:拖拽结束后更新了数组,但Final Form的FieldArray没有及时感知到变化,还是沿用了旧的渲染快照。
具体解决步骤
1. 给列表项设置唯一且稳定的key
别用索引当key!一定要用每个列表项自身的唯一标识(比如item的id),这样React能精准识别每个元素的变化:
{fields.map((name, index) => { const item = fields.value[index]; // 用item的唯一id作为key,而不是index return ( <Draggable key={item.id} draggableId={item.id.toString()} index={index} > {(provided) => ( <div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} > {/* 你的表单字段内容 */} <Field name={`${name}.value`} component="input" /> </div> )} </Draggable> ); })}
2. 确保拖拽结束后正确更新Final Form的字段数组
不要直接修改state,一定要用FieldArray提供的replace方法来更新数组,这样Final Form会触发正确的重新渲染:
const handleDragEnd = (result) => { if (!result.destination) return; // 重新排序数组 const items = Array.from(fields.value); const [movedItem] = items.splice(result.source.index, 1); items.splice(result.destination.index, 0, movedItem); // 用FieldArray的replace方法更新,而不是手动改state fields.replace(items); };
3. 区分拖拽临时元素(可选)
如果还是有问题,可以给拖拽克隆的元素加特殊标识,渲染时跳过它:
<Draggable key={item.id} draggableId={item.id.toString()} index={index} > {(provided, snapshot) => ( // 只有非拖拽状态的元素才正常渲染表单字段 <div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps} style={{ ...provided.draggableProps.style, opacity: snapshot.isDragging ? 0.5 : 1 }} > {!snapshot.isDragging && ( <Field name={`${name}.value`} component="input" /> )} </div> )} </Draggable>
按照这几步调整后,应该就能解决UI重复行的问题了~
备注:内容来源于stack exchange,提问作者shifoc
相关产品推荐
相关产品推荐

