如何在react-querybuilder中过滤FieldSelector已使用字段
解决React Query Builder自定义FieldSelector移除已用字段的问题
问题核心
需要实现:新增规则时FieldSelector仅显示未被使用的字段,但原有规则的FieldSelector仍能保留自身已选字段(支持修改)。之前的错误是直接过滤所有已用字段,导致原有规则的选项被错误移除。
解决方案思路
区分当前FieldSelector所属的规则状态,针对性过滤选项:
- 已存在的规则:保留当前选中的字段,同时显示其他未被使用的字段
- 新增的规则:仅显示未被其他规则使用的字段
关键逻辑是收集已用字段时,排除当前规则自身的字段值,避免把当前规则的选项过滤掉。
修改后的FieldSelector组件代码
const FieldSelector = (props: FieldSelectorProps) => { const { control, setValue, getValues } = useFormContext(); const namePrefix = `${name}[${props.path[0]}]`; const rules = getValues(name); // 获取当前规则的字段值 const currentField = props.value; // 收集已使用的字段,排除当前规则自身的字段 const usedFields = new Set( rules?.filter(rule => rule.field !== currentField) ?.map(rule => rule.field) ); // 分状态过滤选项 const filteredOptions = (props.options as FullOption[]).filter(option => { if (currentField) { // 已存在的规则:保留当前选中字段 + 未被其他规则使用的字段 return option.value === currentField || !usedFields.has(option.value); } // 新增规则:仅显示未被使用的字段 return !usedFields.has(option.value); }); return ( <div className="flex"> <FormField control={control} name={`${namePrefix}.field`} rules={{ required: true }} render={({ field }) => ( <Select value={field.value} onValueChange={(d) => { props.handleOnChange(d); field.onChange(d); if (props.value !== d) { setValue(`${namePrefix}.value`, [], { shouldDirty: true }); } }} disabled={props.disabled} > <SelectTrigger className="h-10 min-w-[120px] w-fit"> <SelectValue placeholder={props.value} data-testid="qb-field-selector" /> </SelectTrigger> <SelectContent side="bottom"> {filteredOptions.map((p: BaseOption, index: number) => ( <SelectItem key={index} value={`${p.value}`}> {p.label} </SelectItem> ))} </SelectContent> </Select> )} /> </div> ); };
关键修改点说明
- 排除当前规则字段:收集已用字段时,通过
filter(rule => rule.field !== currentField)排除当前规则的字段,避免把自身选项过滤掉。 - 分状态过滤选项:
- 当规则已有选中字段,保留当前字段和未被其他规则使用的字段,确保原有规则的FieldSelector能正常显示自身选项。
- 当规则是新增状态,仅显示未被使用的字段,符合新增规则的需求。
- 渲染过滤后的选项:将原来的
props.options替换为filteredOptions,确保下拉框显示正确的选项。
内容的提问来源于stack exchange,提问作者Muhammad Zahid Iqbal
相关产品推荐
相关产品推荐

