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

react-admin筛选变更时清空ReferenceArrayInput选中值问题

问题场景
  • 表单内使用两个关联输入组件,子分类选择组件被FormDataConsumer包裹,依赖分类选择组件的选中值做条件筛选和显隐控制
  • 预期逻辑:选中分类后加载对应子分类选项,修改分类时自动清空已选的子分类值
  • 实际异常:选中分类+对应子分类后,重新修改分类值,之前选中的子分类值会残留,不会自动清空
  • 影响版本:react-admin 4.1.0 到最新master分支均存在该现象
  • 已尝试方案:调用useFormContext()提供的setValue、resetValue方法均未生效,初步怀疑是数组字段特殊机制或缓存导致

原始实现代码如下:

<ArrayInput source={`shops.${shopIndex}.categories`}>
  <SimpleFormIterator disableReordering>
    <ReferenceInput source="categoryId" reference="categories">
      <SelectInput optionText="name" />
    </ReferenceInput>
    <FormDataConsumer>
      {({ formData, getSource, scopedFormData, ...rest }) => {
        // 未选择分类时不渲染,无法筛选子分类
        if (!scopedFormData.categoryId) {
          return null;
        }

        return (
          <SelectArrayInput
            source={getSource('subCategoryIds')}
            reference="subCategories"
            perPage={500}
            filter={{ categories: [scopedFormData.categoryId] }}
          >
            <ReferenceArrayInput optionText="name" />
          </SelectArrayInput>
        );
      }}
    </FormDataConsumer>
  </SimpleFormIterator>
</ArrayInput>

当前子分类筛选、组件显隐切换功能均运行正常,仅缺少分类变更时自动清空已选子分类值的逻辑。

问题根因

ArrayInput嵌套SimpleFormIterator时,每个迭代项的字段路径是带动态数组索引的(例如shops.0.categories.1.subCategoryIds),直接调用全局useFormContext的setValue方法时,若未传入带正确索引的完整字段路径,无法匹配到数组内的目标嵌套字段,方法调用不会生效。同时react-admin默认不会在输入组件因条件渲染卸载时自动清空对应字段值,最终导致旧值残留。

实现方案

不需要额外引入依赖,直接通过作用域内的路径生成方法拿到子分类的完整字段路径,再调用表单更新方法清空值即可,两种实现方式可按需选择:

方案1:给分类选择器增加变更回调

将分类选择器也包裹在FormDataConsumer中,给SelectInput增加onChange事件,每次分类值变更时,先清空当前迭代项的subCategoryIds值,再更新分类值:

<ArrayInput source={`shops.${shopIndex}.categories`}>
  <SimpleFormIterator disableReordering>
    <FormDataConsumer>
      {({ getSource, ...rest }) => (
        <ReferenceInput source="categoryId" reference="categories">
          <SelectInput 
            optionText="name" 
            onChange={(value) => {
              // 通过getSource生成当前迭代项子分类的完整路径,清空旧值
              rest.setValue(getSource('subCategoryIds'), []);
              // 更新选中的分类值
              rest.setValue(getSource('categoryId'), value);
            }}
          />
        </ReferenceInput>
      )}
    </FormDataConsumer>
    <FormDataConsumer>
      {({ formData, getSource, scopedFormData, ...rest }) => {
        if (!scopedFormData.categoryId) {
          return null;
        }

        return (
          <SelectArrayInput
            source={getSource('subCategoryIds')}
            reference="subCategories"
            perPage={500}
            filter={{ categories: [scopedFormData.categoryId] }}
          >
            <ReferenceArrayInput optionText="name" />
          </SelectArrayInput>
        );
      }}
    </FormDataConsumer>
  </SimpleFormIterator>
</ArrayInput>

注意不要使用全局useFormContext返回的setValue,要使用FormDataConsumer透传的setValue,配合getSource生成的路径才能准确命中数组内的嵌套字段。

方案2:子分类渲染逻辑增加关联校验

在FormDataConsumer渲染子分类组件的逻辑中,判断如果当前已选的子分类不属于新选中的分类,直接清空对应值即可,适合子分类和分类关联校验逻辑更复杂的场景。

注意:不要通过给组件加key强制重挂载的方式清空值,会导致选项缓存丢失、接口重复请求,性能损耗更高。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:12:24