React如何实现多个select下拉框选项互斥,选中后从其余下拉框移除且取消可恢复
问题根源
你的代码核心问题有三个:
- 没有留存全量原始选项池,直接修改初始选项数组导致被删除的选项无法找回
- 选中值更新逻辑没有处理旧选中值的回收,切换选项时旧值不会自动回到选项池
- 直接用
splice修改state引用属于状态突变,可能导致React无法触发正确的重渲染
实现方案
不需要单独维护可选选项的state,直接基于全量原始选项和已选中值动态计算每个下拉框的可选列表,逻辑更简单也不会出现值丢失的问题。
修改后完整代码
// 单独定义全量原始选项,不要放在state里 const ALL_OPTIONS = ['--', '1', '2', '3', '4', '5', '6'] const [selectedValue, setSelectedValue] = useState({ box1: '--', box2: '--', box3: '--', box4: '--', box5: '--', box6: '--', }) const handleChange = (e) => { const { name, value } = e.target setSelectedValue({ ...selectedValue, [name]: value }) } // 封装获取单个下拉框可选选项的方法 const getOptionsForBox = (boxName) => { // 收集所有其他下拉框已选中的非默认值 const otherSelectedValues = Object.entries(selectedValue) .filter(([name, val]) => name !== boxName && val !== '--') .map(([_, val]) => val) // 过滤掉其他下拉已选的值,返回当前下拉可用的选项 return ALL_OPTIONS.filter(opt => !otherSelectedValues.includes(opt)) }
下拉框渲染部分只需修改map的数据源即可,示例如下:
<Box className={classes.columnBox}> <TextField select name='box1' value={selectedValue.box1} onChange={handleChange}> {getOptionsForBox('box1').map(option => { return ( <MenuItem key={option} value={option}>{option}</MenuItem> ) })} </TextField> </Box> <Box className={classes.columnBox}> <Typography>{selectedValue.box2}</Typography> <TextField select name='box2' value={selectedValue.box2} onChange={handleChange}> {getOptionsForBox('box2').map(option => { return ( <MenuItem key={option} value={option}>{option}</MenuItem> ) })} </TextField> </Box> {/* box3到box6都按照上述逻辑修改map部分即可 */}
逻辑说明
- 所有下拉框的可选列表都会自动排除其他下拉已经选中的非默认值,自己选中的值会保留在自己的选项列表里,不会出现值超出范围的问题
- 切换选项或者选择默认值
--时,之前被占用的选项会自动回到所有下拉的可选列表里,不需要额外的新增/删除选项逻辑 - 完全避免了直接修改state的问题,所有状态更新都是不可变的,符合React的状态更新规范
内容的提问来源于stack exchange,提问作者sargi_bruno
相关产品推荐
相关产品推荐

