我尝试使用 ReactJS 和 antd Form 创建 Form 表单中的每一行都需要根据用户在该行中第一个元素中的选择来呈现不同的元素(输入/选择) 例如,参见图片:
第一行工作正常,问题从第二行开始 -> 当我更改“param”中的值时,它会更改所有行中的第三个输入元素类型
我在这里添加了代码:
https://codesandbox.io/p/sandbox/select-row-gcsfzj?file=%2Fsrc%2FApp.tsx%3A33%2C30-33%2C35
重现我的问题的步骤:
知道如何解决这个问题吗? 提前致谢!
我尝试将表单与 Form.List 一起使用,但结果相同。
您正在使用相同的
selectedParam
状态来处理多行。因此,如果更新其中一行 param
,它将更新所有其他行。
其次你没有正确使用antd List。当迭代 Form.List 提供的
fields
数组时,每个字段/项目都会有一个数字类型的键 name
。您可以将其称为该字段的索引。由于每行有 3 个字段,您可以为每个字段分配一个键,以便它以表格形式存储在特定索引处,如下所示 <Form.Item name={[field.name, "param"]}>...
。请注意,您不需要在 name
开始之前添加 Form.List name={[field.name, "param"]}
,因为它已经由 antd 添加了。
现在基于每一行选定的参数,您想要渲染一个自定义字段,例如输入,选择...我创建了一个组件
DynamicField
,它接受name
作为道具(您可以说该特定字段的索引) /row...) 并使用 Form.useWatch
,我监听特定的 Form 值并相应地渲染字段。这里需要传递完整的名称路径。
这是完整的代码。
import { Button, Form, Input, Select, type SelectProps, Space } from 'antd';
type FormType = { transactionFilter: Array<{ param: string; operator: string; value: string }> };
const paramOptions: SelectProps['options'] = [
{ label: 'param-1', value: 'param-1' },
{ label: 'param-2', value: 'param-2' },
{ label: 'param-3', value: 'param-3' }
];
const operatorOptions: SelectProps['options'] = [
{ label: 'operator-1', value: 'operator-1' },
{ label: 'operator-2', value: 'operator-2' }
];
export default function App() {
const [form] = Form.useForm<FormType>();
const onFinish = (values: FormType) => {
console.log('Received values of form:', values);
};
return (
<Form onFinish={onFinish} className='my-form' form={form}>
<Form.List name='transactionFilter'>
{(fields, { add }) => (
<div id='second-div' style={{ display: 'flex', rowGap: 16, flexDirection: 'column' }}>
{fields.map((field) => (
<div key={field.key} id='3rd-div'>
<Space>
<Form.Item label='param' name={[field.name, 'param']}>
<Select style={{ width: 120 }} placeholder='params' options={paramOptions} />
</Form.Item>
<Form.Item label='operator' name={[field.name, 'operator']}>
<Select style={{ width: 120 }} placeholder='operator' options={operatorOptions} />
</Form.Item>
<DynamicField name={field.name} />
</Space>
</div>
))}
<Button onClick={() => add()}>+ Add Row</Button>
</div>
)}
</Form.List>
</Form>
);
}
const DynamicField = ({ name }: { name: number }) => {
const param = Form.useWatch(['transactionFilter', name, 'param']);
if (param === 'param-1') {
return (
<Form.Item label='text' name={[name, 'value']}>
<Input placeholder='value-text-input' />
</Form.Item>
);
}
if (param === 'param-2') {
return (
<Form.Item label='select' name={[name, 'value']}>
<Select
style={{ width: 150 }}
placeholder={'Select-input'}
options={[
{ label: 'value-1', value: 'value-1' },
{ label: 'value-2', value: 'value-2' }
]}
/>
</Form.Item>
);
}
return null;
};