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

如何获取存于变量/Props中的Ant Design Form表单元素值?

问题:动态生成的Form.Item无法被Ant Design Form捕获值

我通过模板替换生成包含<Form.Item>和<Input>的HTML字符串,再用html-react-parser解析成React元素(赋值给body变量)嵌入Form组件。提交表单时获取到的是空对象,但直接编写<Form.Item>搭配<Input>就能正常取值。

模板内容

<p><strong>Commercial start of +++SERVICE+++</strong> <strong>roaming service</strong></p><p><strong>between,</strong></p><p><strong>+++OPERATOR_A+++, +++COUNTRY_A+++ (+++TADIG_A+++)</strong></p><p>&amp;</p><p><strong>+++OPERATOR_B+++, +++COUNTRY_B+++ (+++TADIG_B+++)</strong></p><p>This is to confirm that on <strong>+++LAUNCH_DATE+++</strong></p><p>Agree to launch +++SERVICE+++ service on a bilateral basis. The launch follows the successful completion of the applicable IREG and TADIG tests.</p><table><tr><td><p><strong>For +++OPERATOR_A+++</strong></p><p><strong>Date: +++SIGNATURE_DATE+++</strong></p><p><strong>+++RESPONSIBLE_A_NAME+++</strong></p><p><strong>Title: +++RESPONSIBLE_A_DESIGNATION+++</strong></p><p><strong>+++IMAGE signature()+++</strong></p></td><td><p><strong>For +++OPERATOR_B+++</strong></p><p><strong>           Date: </strong></p><p><strong>+++RESPONSIBLE_B_NAME+++</strong></p><p><strong>Title: +++RESPONSIBLE_B_DESIGNATION+++</strong></p></td></tr></table>

原代码

import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
import {message, Form, Button , Input} from 'antd';
import React, { useState } from 'react';
import './HtmlContract.css';
import parse from 'html-react-parser';
const layout = {
    labelCol: {
        span: 8,
    },
    wrapperCol: {
        span: 16,
    },
}


function HtmlContract(props) {
    const [html, setHtml] = useState(props.templateContract.value);
    const replaceInputsAndImages = () => {
        if (html.includes('+++')) {
            let mySubString = html.substring(
                html.indexOf("+++") + 3,
                html.indexOf("+++", html.indexOf("+++") + 3)
            );
            setHtml(html.replaceAll("+++" + mySubString + "+++",`<Form.Item label='${mySubString}' name='${mySubString}'><Input placeholder='${mySubString}' /></Form.Item> `));
    }};
    const [loading, setLoading] = useState(false);
    const [form] = Form.useForm()
    React.useEffect(() => {
        replaceInputsAndImages();
    });

    const onFinish = async (values) => {
        console.log(values)
        
    }
    const body = parse(html);

    return (<>

                <Form
                    onFinish={onFinish}
                    onFinishFailed={(errorInfo) => console.log(errorInfo)}
                    form={form}
                    {...layout}
                    name='contract-form'>
                        {body}
                        <Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 8 }}>
                            <Button type='primary' htmlType='submit' style={{ float: 'right' }}>
                                Save
                            </Button>
                        </Form.Item>
                </Form>
        </>
    );
}

export default HtmlContract;

核心原因

  1. 上下文关联失效:Ant Design Form通过React上下文(Context)管理字段状态,html-react-parser解析生成的<Form.Item>是孤立的React元素,没有接入外层Form的上下文,导致Form无法识别这些动态字段。
  2. 替换逻辑缺陷:原代码的replaceInputsAndImages每次仅替换一个变量,且useEffect无依赖项,会触发无限循环渲染,进一步加剧状态混乱。

解决方案

方案1:直接生成React元素(推荐)

跳过HTML字符串解析步骤,直接从模板提取变量并生成<Form.Item>组件,确保字段与Form上下文正常关联:

import { Form, Button, Input } from 'antd';
import React, { useState, useEffect } from 'react';
import './HtmlContract.css';

const layout = {
    labelCol: { span: 8 },
    wrapperCol: { span: 16 },
}

// 提取模板中的所有变量
const extractVariables = (html) => {
    const regex = /\+\+\+([^+]+)\+\+\+/g;
    const uniqueVars = new Set();
    let match;
    while ((match = regex.exec(html)) !== null) {
        // 过滤图片类型变量
        if (!match[1].startsWith('IMAGE')) {
            uniqueVars.add(match[1]);
        }
    }
    return Array.from(uniqueVars);
}

function HtmlContract(props) {
    const [templateHtml] = useState(props.templateContract.value);
    const [formFields, setFormFields] = useState([]);
    const [form] = Form.useForm()

    useEffect(() => {
        const variables = extractVariables(templateHtml);
        // 动态生成Form.Item组件数组
        const fields = variables.map(name => (
            <Form.Item key={name} label={name} name={name}>
                <Input placeholder={name} />
            </Form.Item>
        ));
        setFormFields(fields);
    }, [templateHtml]);

    const onFinish = (values) => {
        console.log(values)
    }

    return (
        <Form
            onFinish={onFinish}
            onFinishFailed={(errorInfo) => console.log(errorInfo)}
            form={form}
            {...layout}
            name='contract-form'>
            {formFields}
            <Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 8 }}>
                <Button type='primary' htmlType='submit' style={{ float: 'right' }}>
                    Save
                </Button>
            </Form.Item>
        </Form>
    );
}

export default HtmlContract;

方案2:保留原HTML结构的混合渲染

如果需要保留模板中的段落、表格等结构,可拆分模板文本与变量,插入对应的Form字段:

import { Form, Button, Input } from 'antd';
import React, { useState, useEffect } from 'react';
import './HtmlContract.css';
import parse from 'html-react-parser';

const layout = {
    labelCol: { span: 8 },
    wrapperCol: { span: 16 },
}

const extractVariables = (html) => {
    const regex = /\+\+\+([^+]+)\+\+\+/g;
    const uniqueVars = new Set();
    let match;
    while ((match = regex.exec(html)) !== null) {
        if (!match[1].startsWith('IMAGE')) {
            uniqueVars.add(match[1]);
        }
    }
    return Array.from(uniqueVars);
}

// 解析模板,替换变量为对应Form字段
const parseTemplate = (html, fieldsMap) => {
    const regex = /\+\+\+([^+]+)\+\+\+/g;
    const parts = html.split(regex);
    return parts.map((part, index) => {
        if (fieldsMap[part]) {
            return fieldsMap[part];
        }
        // 解析普通HTML文本
        return parse(part);
    });
}

function HtmlContract(props) {
    const [templateHtml] = useState(props.templateContract.value);
    const [content, setContent] = useState([]);
    const [form] = Form.useForm()

    useEffect(() => {
        const variables = extractVariables(templateHtml);
        const fieldsMap = {};
        variables.forEach(name => {
            fieldsMap[name] = (
                <Form.Item key={name} label={name} name={name}>
                    <Input placeholder={name} />
                </Form.Item>
            );
        });
        // 生成包含原HTML结构和Form字段的内容
        const parsedContent = parseTemplate(templateHtml, fieldsMap);
        setContent(parsedContent);
    }, [templateHtml]);

    const onFinish = (values) => {
        console.log(values)
    }

    return (
        <Form
            onFinish={onFinish}
            onFinishFailed={(errorInfo) => console.log(errorInfo)}
            form={form}
            {...layout}
            name='contract-form'>
            {content}
            <Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 8 }}>
                <Button type='primary' htmlType='submit' style={{ float: 'right' }}>
                    Save
                </Button>
            </Form.Item>
        </Form>
    );
}

export default HtmlContract;

方案3:修复原代码的循环问题(仅辅助,无法解决核心取值问题)

若暂时保留原HTML解析方式,需先修复无限循环:

React.useEffect(() => {
    replaceInputsAndImages();
}, [html]); // 添加html作为依赖,避免无限循环

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 09:57:55