React实现动态下拉菜单删除项时UI渲染错误问题求助
问题根因
删除后UI显示错位是两个错误共同导致的:
- 渲染下拉列表时使用数组
index作为key属性:React依靠key识别列表元素是否需要更新,删除某一项后后续元素的index会整体前移,React会误判你删除的是列表最后一项,最终表现就是删除项和实际消失的项不匹配 - 下拉的
name属性、提交时的唯一标识都依赖动态变化的index:删除操作后index变动,导致你存在reducer里的字段名和实际渲染的下拉字段名无法对应
修复步骤
1. 给每个新增下拉项生成固定唯一ID
不要直接把选项数组存入disciplinesDropdowns,改成存包含固定ID的对象,ID在新增下拉时生成,后续不会变动:
// 简单场景用自增ID即可,复杂场景可以替换为uuid生成 let dropdownAutoId = 0; export default function Discipline({ registration, handleRemoveDisciplineClick, handleSelectDisciplineClick }) { const [disciplinesDropdowns, setDisciplinesDropdowns] = useState([]); const handleAddDisciplineClick = () => { setDisciplinesDropdowns((prev) => [...prev, { id: dropdownAutoId++, options: disciplines_fake_data }]); };
2. 替换所有动态index的应用场景
用固定ID代替index作为列表key、下拉name属性的生成依据、删除的匹配条件:
const handleRemoveDropdownClick = (targetId) => { // 按ID过滤要删除的下拉项 const newList = disciplinesDropdowns.filter(item => item.id !== targetId); setDisciplinesDropdowns(newList); // 字段名用固定ID生成,不受index变动影响 handleRemoveDisciplineClick(`otherDisciplines_${targetId}`); }; return ( <div> <div> {disciplinesDropdowns.length > 0 && disciplinesDropdowns.map((item, index) => ( {/* key使用固定ID */} <div style={{ marginTop: "10px" }} key={item.id}> <article> <label htmlFor={`otherDisciplines_${item.id}`}> Discipline {index + 1} </label> <button onClick={(e) => { e.preventDefault(); handleRemoveDropdownClick(item.id); }} > REMOVE </button> </article> <select defaultValue="choose from all disciplines" {/* name属性用固定ID生成 */} name={`otherDisciplines_${item.id}`} onChange={handleSelectDisciplineClick} > <option disabled value="choose from all disciplines"> -choose from all disciplines- </option> {item.options.map((discipline) => ( <option key={discipline.id} value={discipline.name}> {discipline.name} </option> ))} </select> </div> ))}
3. 可选优化reducer逻辑
原有SELECT_DISCIPLINES分支存在冗余逻辑,可以优化为直接更新已有字段,不需要重复新增后去重:
case FORM_ACTION.SELECT_DISCIPLINES: const name = action.payload.name; const value = action.payload.value; const existedIndex = state.otherDisciplines.findIndex(d => Object.keys(d)[0] === name); const newDisciplines = [...state.otherDisciplines]; if (existedIndex > -1) { newDisciplines[existedIndex] = { [name]: value }; } else { newDisciplines.push({ [name]: value }); } return { ...state, otherDisciplines: newDisciplines };
内容的提问来源于stack exchange,提问作者Angie
相关产品推荐
相关产品推荐

