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

MUI v5 Select组件重复选项多选异常问题处理咨询

MUI v5 解决多选Select组件重复选项选中问题

问题说明

使用MUI v5的多选Select组件时,若存在名称重复的选项,选择其中一个会导致所有同名选项被同时选中。这是因为当前代码使用**名称(name)**作为选项的value,而重复的名称无法被组件区分。

原代码

import * as React from "react";
import OutlinedInput from "@mui/material/OutlinedInput";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import ListItemText from "@mui/material/ListItemText";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import Checkbox from "@mui/material/Checkbox";

const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250
    }
  }
};

const namesObj = [
  {
    id: 1,
    name: "Oliver Hansen"
  },
  {
    id: 2,
    name: "Van Henry"
  },
  {
    id: 3,
    name: "April Tucker"
  },
  {
    id: 4,
    name: "April Tucker"
  }
];

export default function MultipleSelectCheckmarks() {
  const [personName, setPersonName] = React.useState<string[]>([]);
  console.log("personName: ", personName);
  const handleChange = (event: SelectChangeEvent<typeof personName>) => {
    const {
      target: { value }
    } = event;
    setPersonName(
      // On autofill we get a stringified value.
      typeof value === "string" ? value.split(",") : value
    );
  };

  return (
    <div>
      <FormControl sx={{ m: 1, width: 300 }}>
        <InputLabel id="demo-multiple-checkbox-label">Tag</InputLabel>
        <Select
          labelId="demo-multiple-checkbox-label"
          id="demo-multiple-checkbox"
          multiple
          value={personName}
          onChange={handleChange}
          input={<OutlinedInput label="Tag" />}
          renderValue={(selected) => selected.join(", ")}
          MenuProps={MenuProps}
        >
          {namesObj.map((name) => (
            <MenuItem key={name.id} value={name.name}>
              <Checkbox checked={personName.indexOf(name.name) > -1} />
              <ListItemText primary={name.name} />
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

解决方案

核心思路是使用**唯一标识(id)**作为选项的value,而非重复的名称,让组件能精准区分每个选项。具体修改点如下:

  • 状态类型调整:将存储选中项的变量从string[]改为number[],存储选中项的id而非名称
  • 选项值替换:MenuItem的value从name.name改为name.id
  • 选中状态判断:Checkbox的checked逻辑改为检查当前id是否在选中数组中
  • 显示值映射:renderValue方法将选中的id转换为对应的名称,保持界面显示不变
  • 事件处理调整:确保handleChange中处理的是id数组

修改后的完整代码

import * as React from "react";
import OutlinedInput from "@mui/material/OutlinedInput";
import InputLabel from "@mui/material/InputLabel";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import ListItemText from "@mui/material/ListItemText";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import Checkbox from "@mui/material/Checkbox";

const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
  PaperProps: {
    style: {
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
      width: 250
    }
  }
};

const namesObj = [
  {
    id: 1,
    name: "Oliver Hansen"
  },
  {
    id: 2,
    name: "Van Henry"
  },
  {
    id: 3,
    name: "April Tucker"
  },
  {
    id: 4,
    name: "April Tucker"
  }
];

export default function MultipleSelectCheckmarks() {
  // 存储选中项的id,类型改为number数组
  const [selectedIds, setSelectedIds] = React.useState<number[]>([]);
  console.log("selectedIds: ", selectedIds);

  const handleChange = (event: SelectChangeEvent<typeof selectedIds>) => {
    const { target: { value } } = event;
    setSelectedIds(
      typeof value === "string" ? value.split(",").map(Number) : value
    );
  };

  // 根据id获取对应的名称,用于显示
  const getSelectedNames = () => {
    return selectedIds.map(id => {
      const item = namesObj.find(item => item.id === id);
      return item ? item.name : "";
    }).join(", ");
  };

  return (
    <div>
      <FormControl sx={{ m: 1, width: 300 }}>
        <InputLabel id="demo-multiple-checkbox-label">Tag</InputLabel>
        <Select
          labelId="demo-multiple-checkbox-label"
          id="demo-multiple-checkbox"
          multiple
          value={selectedIds}
          onChange={handleChange}
          input={<OutlinedInput label="Tag" />}
          renderValue={getSelectedNames}
          MenuProps={MenuProps}
        >
          {namesObj.map((item) => (
            <MenuItem key={item.id} value={item.id}>
              <Checkbox checked={selectedIds.includes(item.id)} />
              <ListItemText primary={item.name} />
            </MenuItem>
          ))}
        </Select>
      </FormControl>
    </div>
  );
}

说明

修改后,组件通过唯一id识别每个选项,即使名称重复也能独立选中/取消选中。界面上依然显示选项名称,但实际存储的是唯一id,避免了重复值导致的选中异常。

内容的提问来源于stack exchange,提问作者asus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:47:49