React项目中react-movable组件删除元素显示异常问题求助
React-Movable 删除元素时渲染异常问题修复
问题描述
使用react-movable库实现尺寸(S/M/L/XL)的增删改与拖拽排序功能,通过ContextAPI维护data.sizes数组,本地用tempSize状态同步数据。删除元素时,控制台输出的更新后数组正确,但页面渲染出现异常:例如删除S时,页面显示XL被移除,且S莫名变为禁用状态。
核心原因
- 列表项缺少唯一Key:react-movable的
renderItem返回的<li>未设置唯一key,React列表渲染时无法正确识别元素,导致DOM节点复用错误,引发内容和状态(如禁用属性)错位。 - 拖拽状态更新的闭包问题:拖拽
onChange中使用setTimeout和直接引用tempSize,闭包捕获旧状态值,导致排序后的状态更新错误,破坏后续操作的状态一致性。 - 双状态同步冲突:删除操作同时手动更新
tempSize和Context的data.sizes,useEffect监听data.sizes后又会同步tempSize,引发状态覆盖或不一致。
解决方案
1. 为列表项添加唯一标识
在renderItem的<li>上绑定唯一key(使用元素的id):
renderItem={({ value, index, props }) => ( <li {...props} key={value.id}> <input type="text" defaultValue={!value.title ? value.size : value.title} disabled={value.title === "M" || value.size === "M"} onKeyUp={(e) => onChangeName(value.id, e.target.value)} /> <button type="button" className={styles.remove_btn} onClick={() => onRemoveMeasurement(value.title, value.id)} ></button> </li> )}
2. 修复拖拽排序的状态更新逻辑
移除setTimeout和清空数组的操作,使用函数式更新获取最新状态,同时保证数组不可变性:
<List values={tempSize} onChange={({ oldIndex, newIndex }) => { // 函数式更新获取最新状态,拷贝数组避免修改原引用 setTempSize(prevState => arrayMove([...prevState], oldIndex, newIndex)); }} renderList={({ children, props }) => <ul {...props}>{children}</ul>} {/* renderItem 不变 */} />
3. 简化删除操作的状态同步
删除时仅更新Context的data.sizes,依赖useEffect自动同步tempSize,避免手动双状态更新的冲突:
const onRemoveMeasurement = async (title, id) => { if (title === "M") { console.log("You can't remove the 'M' size."); } else { const updatedDataSizes = data.sizes.filter((item) => item.id !== id); data.setSizes(updatedDataSizes); } };
4. 优化useEffect的状态同步
确保tempSize始终是新数组拷贝,避免引用共享导致的更新异常:
useEffect(() => { // 拷贝data.sizes生成新数组,保证状态更新的可追踪性 setTempSize([...data.sizes]); }, [data.sizes]);
验证效果
修复后,删除元素时页面会正确渲染更新后的列表,禁用状态不再错位,拖拽排序功能也能正常工作,控制台数据与页面显示保持一致。
内容的提问来源于stack exchange,提问作者mrconcerned
相关产品推荐
相关产品推荐

