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

React-Admin中如何通过OnChange修改ArrayInput内嵌套字段值

解决React Admin中嵌套配料字段的关联选择与更新问题

核心解决思路

  • 遍历配料数组时,显式传递当前项的索引给自定义组件
  • 用React Admin的useFormContext或FormDataConsumer获取表单操作方法,精准更新对应索引的嵌套字段
  • 严格区分字段路径,避免误修改顶级字段(比如饮品名称)

1. 饮品编辑视图的基础结构

在编辑视图中,通过ArrayInput+SimpleFormIterator遍历配料数组,同时将当前项索引传递给自定义选择组件:

import { Edit, SimpleForm, TextInput, ArrayInput, SimpleFormIterator } from 'react-admin';
import IngredientSelect from './IngredientSelect';

const DrinksEdit = () => (
    <Edit title="编辑饮品">
        <SimpleForm>
            <TextInput source="name" label="饮品名称" />
            {/* 遍历配料数组,传递当前项索引给自定义组件 */}
            <ArrayInput source="ingredients" label="配料">
                <SimpleFormIterator>
                    <IngredientSelect idx={props.index} />
                    <TextInput source="quantity" label="数量" />
                </SimpleFormIterator>
            </ArrayInput>
        </SimpleForm>
    </Edit>
);

2. 自定义配料选择组件实现

利用useReferenceInputController处理关联资源选择,通过useFormContext的setValue精准更新对应索引的嵌套字段:

import { useReferenceInputController, SelectInput, useFormContext } from 'react-admin';

const IngredientSelect = ({ idx }) => {
    const { setValue } = useFormContext();
    const {
        options,
        loading,
        error,
        setValue: setReferenceId,
    } = useReferenceInputController({
        source: `ingredients[${idx}]._id`,
        reference: 'ingredients',
        perPage: 20,
    });

    const handleSelect = (value) => {
        // 设置关联ID
        setReferenceId(value);
        // 从选项中获取选中配料的完整数据
        const selected = options.find(opt => opt.value === value);
        if (selected) {
            // 更新对应索引的name和unit字段
            setValue(`ingredients[${idx}].name`, selected.label);
            setValue(`ingredients[${idx}].unit`, selected.data?.unit);
        }
    };

    return (
        <SelectInput
            label="选择配料"
            source={`ingredients[${idx}]._id`}
            choices={options}
            loading={loading}
            error={error}
            onChange={handleSelect}
            optionText="name"
        />
    );
};

export default IngredientSelect;

3. 用FormDataConsumer的替代写法

如果偏好使用FormDataConsumer,可以这样确保字段路径和索引正确:

<ArrayInput source="ingredients">
    <SimpleFormIterator>
        <FormDataConsumer>
            {({ getSource, setValue, index }) => {
                const { options, loading, error } = useReferenceInputController({
                    source: getSource('_id'),
                    reference: 'ingredients',
                });

                return (
                    <SelectInput
                        label="选择配料"
                        source={getSource('_id')}
                        choices={options}
                        loading={loading}
                        error={error}
                        onChange={(value) => {
                            setValue(getSource('_id'), value);
                            const selected = options.find(opt => opt.value === value);
                            if (selected) {
                                setValue(getSource('name'), selected.label);
                                setValue(getSource('unit'), selected.data.unit);
                            }
                        }}
                        optionText="name"
                    />
                );
            }}
        </FormDataConsumer>
    </SimpleFormIterator>
</ArrayInput>

关键注意事项

  • 所有嵌套字段的路径必须写成ingredients[${idx}].xxx,绝对不能直接用name或unit,否则会误改顶级的饮品名称字段
  • 必须通过SimpleFormIterator的index属性获取当前项的索引,确保更新的是对应位置的配料数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:18:36