ReactJS - 生成具有多个动态行的 ant.d 表单

问题描述 投票:0回答:1

我尝试使用 ReactJS 和 antd Form 创建 Form 表单中的每一行都需要根据用户在该行中第一个元素中的选择来呈现不同的元素(输入/选择) 例如,参见图片: enter image description here

第一行工作正常,问题从第二行开始 -> 当我更改“param”中的值时,它会更改所有行中的第三个输入元素类型

我在这里添加了代码:

https://codesandbox.io/p/sandbox/select-row-gcsfzj?file=%2Fsrc%2FApp.tsx%3A33%2C30-33%2C35

重现我的问题的步骤:

  1. 添加行
  2. 在“param”中选择 param-1 值,该行中的第三个元素现在是“文本输入”
  3. 添加新行
  4. 在“param”中选择param-2值,现在第三个元素类型是“Select”,但所有其他行也已更改,我只需要更改当前行并保持所有其他行不变。

知道如何解决这个问题吗? 提前致谢!

我尝试将表单与 Form.List 一起使用,但结果相同。

reactjs forms antd
1个回答
0
投票

您正在使用相同的

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;
};
© www.soinside.com 2019 - 2024. All rights reserved.