You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 14:15:01