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
相关产品推荐
相关产品推荐

