React Material UI 如何根据关联值自动移除Autocomplete已选项
问题描述
基于 Material UI Autocomplete 组件开发两级联动多选框,参考官方复选框用法实现,需要解决主分类取消选中时,对应已选子分类自动清除的联动问题,具体边界场景:
- 主行业选择框同时选中「Consumer Electronics」「Fashion & Apparel」两个选项
- 子行业选择框分别选中两个主分类下的子项:Consumer Electronics 下的「Computer & Laptops」、Fashion & Apparel 下的「Eyewear」
- 后续在主行业选择框移除「Fashion & Apparel」时,子行业选择框中所有归属该分类的已选子项需要同步自动移除
功能效果截图:
在线可运行示例:CodeSandbox Demo
当前子行业选择框已经通过filterOptions实现选项过滤,仅展示和已选主行业匹配的子行业选项,原始数据结构可查看示例项目中的data.json,现有子行业选择框核心代码如下:
return ( <Autocomplete multiple options={subIndustries} filterOptions={(x) => x.filter((x) => getValues("main_industries").find((m) => m.name === x.category) ) } groupBy={(option) => option.category} disableCloseOnSelect getOptionLabel={(option) => option.name} onChange={(_, newValue: any) => { setValue("sub_industries", newValue, { shouldValidate: true }); }} defaultValue={getValues("sub_industries")} onInputChange={(_, val) => { console.log(val); }} renderOption={(props, option, { selected }) => ( <li {...props}> <Checkbox icon={uncheckedIcon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} /> {option.name} </li> )} renderInput={(params) => ( <TextField {...params} label="Sub Industries" placeholder="Sub Industries" /> )} /> );
实现方案
核心逻辑是监听主行业选中值的变化,每次主行业选中项变更时,自动校验已选子行业的合法性,剔除所属主行业已被取消选中的子项即可。
- 监听表单中
main_industries字段的变化 - 主行业选中项更新后,过滤当前已选的子行业列表,仅保留所属分类存在于最新主行业选中列表中的子项
- 将过滤后的合法子项更新到
sub_industries表单字段,同步更新组件视图 - 将子行业Autocomplete从非受控改为受控模式,避免表单值和视图展示不一致
核心代码
// 监听主行业选中值变化 const selectedMainIndustries = watch("main_industries"); useEffect(() => { const currentSubList = getValues("sub_industries") || []; // 过滤掉归属主行业已被移除的子项 const validSubList = currentSubList.filter(subItem => selectedMainIndustries.some(mainItem => mainItem.name === subItem.category) ); // 更新子行业字段值,触发校验 setValue("sub_industries", validSubList, { shouldValidate: true }); }, [selectedMainIndustries, getValues, setValue]);
调整子行业Autocomplete的属性,将原来的defaultValue替换为受控的value绑定,保证值同步:
<Autocomplete multiple options={subIndustries} // 替换defaultValue为受控value绑定 value={watch("sub_industries") || []} filterOptions={(options) => options.filter(opt => selectedMainIndustries.some(main => main.name === opt.category) ) } groupBy={(option) => option.category} disableCloseOnSelect getOptionLabel={(option) => option.name} onChange={(_, newValue) => { setValue("sub_industries", newValue, { shouldValidate: true }); }} // 其余原有属性(renderOption、renderInput等)保持不变 // ... />
内容的提问来源于stack exchange,提问作者Kay
相关产品推荐
相关产品推荐

