React删除列表中间项时出现最后一项被移除的异常问题求助
问题根因
你遇到的输入框内容移位问题由三个错误实现共同导致:
- 不该将React组件实例直接存储在state中,state仅应存储纯业务数据,直接存组件实例会导致实例和状态强绑定,无法正常触发更新
- 列表渲染时未设置唯一key属性,React虚拟DOM diff默认会用数组索引作为key,删除中间元素后后续元素索引整体前移,React会判定删除的是最后一个元素,仅移除末尾DOM、复用前面的DOM节点
- ListElement的输入框为未受控组件,输入的内容仅存储在DOM节点本身,没有和React状态绑定,DOM复用时之前输入的内容会被保留,自然出现移位
修复方案
父组件代码
import { useState } from 'react'; import ListElement from './ListElement'; import { MdRemoveCircleOutline } from 'react-icons/md'; export default function ListPage() { // state仅存储列表纯数据,每个项配备唯一id const [itemList, setItemList] = useState([]); const removeItem = (id) => { const updatedList = itemList.filter(item => item.id !== id); setItemList(updatedList); }; const addItem = () => { const newItem = { id: Date.now(), // 用时间戳生成唯一id inputValue: '' }; setItemList([...itemList, newItem]); }; // 同步子组件输入框的值到上层状态 const syncInputValue = (id, newValue) => { setItemList(itemList.map(item => { return item.id === id ? {...item, inputValue: newValue} : item; })); }; return ( <div className="list-page"> <div className="list-page-title"> <h2>Create your own List</h2> <br></br> <h4>Create your own list</h4> </div> <input className="title-input" type="text" placeholder="Enter Title" /> <div className="list-content"> {itemList.map((item) => { return ( // 用唯一id作为key,禁止用数组索引 <div key={item.id}> <ListElement handleRemove={() => removeItem(item.id)} value={item.inputValue} onInputChange={(val) => syncInputValue(item.id, val)} /> </div> ); })} </div> <button className="add-button" onClick={addItem}> <span className="list-page-button-icon">+</span>Add Item </button> </div> ); }
ListElement组件代码
export default function ListElement(props) { return ( <div className="list-item"> <input className="item-input" type="text" value={props.value} onChange={(e) => props.onInputChange(e.target.value)} placeholder="请输入内容" ></input> <MdRemoveCircleOutline className="remove-button" onClick={props.handleRemove} /> </div> ); }
内容的提问来源于stack exchange,提问作者bmarcu
相关产品推荐
相关产品推荐

