首页 > 解决方案 > 如何将表单数据从孩子读入父母?

问题描述

我正在使用手动制作的表单生成器并使用React Final Form来管理状态和数据。现在的问题是,我需要从表单外部的组件读取数据,甚至在提交之前向用户显示输入的实际状态。

import React, { Component } from 'react'
import PropTypes from 'prop-types';
import { I18n } from 'react-i18nify';
import * as INPUTTYPES from '../../constants/inputTypes';
import { CONCAT_ID_BASES } from '../../constants/config';
import 'babel-polyfill';
import { Form, Field } from 'react-final-form'
const weblog = require('webpack-log');
const log = weblog({ name: 'wds' }) // webpack-dev-server

class FormGenerator extends Component {
    static propTypes = {
        fields: PropTypes.any,
        prefix: PropTypes.any,
        children: PropTypes.any
    }

    state = {
        data: {}
    }

    sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

    onSubmit = async values => {
        await this.sleep(300)
        window.alert(JSON.stringify(values, 0, 2))
    }

    static simpleMemoize = fn => {
        let lastArg
        let lastResult
        return arg => {
            if (arg !== lastArg) {
                lastArg = arg
                lastResult = fn(arg)
            }
            return lastResult
        }
    }

    static textValidate = FormGenerator.simpleMemoize(async value => {
        if (!value) {
            return I18n.t('error-no-text-written');
        }
        //await sleep(400)
        if (value.trim().length() > 0) {
            return I18n.t('error-no-text-found');
        }
    })

    static createInput = (newKey, value, validate) => {
        let data = {
            type: value.type,
            //disabled: typeof value.editable !== "undefined" ? !value.editable : false,
            className: "form-control",
            id: `${newKey}`,
            value: value.value
        }
        return <Field key={newKey} name={data.id} validate={validate}>
            {({ input, meta }) => (
                <div className="form-group col-md-6">
                    <label htmlFor={`${newKey}`}>{I18n.t(`${newKey}`)}</label>
                    <input {...data} {...input} />
                    {meta.error && meta.touched && <span>{meta.error}</span>}
                </div>
            )}
        </Field>
    }

    static createSelectInput = (newKey, value) => {
        let data = {
            type: value.type,
            disabled: typeof value.editable !== "undefined" ? !value.editable : false,
            className: "form-control",
            id: `${newKey}`,
            value: value.value
        }
        return <React.Fragment key={newKey}>
            <div className="form-group col-md-6">
                <label htmlFor={`${newKey}`}>{I18n.t(`${newKey}`)}</label>
                <input {...data} />
            </div>
        </React.Fragment>
    }

    initialValues = function () {
        let { prefix, fields } = this.props;
        prefix = prefix ? prefix + CONCAT_ID_BASES : '';
        fields ? fields.map((field) => {
            const newKey = `${prefix}${field.key}`
            this.setState((prevState) => {
                let newData = { ...prevState.data };
                newData[newKey] = field.value.value;
                return { data: newData };
            })
        }) : null;
    }

    componentDidMount() {
        this.initialValues();
    }

    componentDidUpdate() {
        //console.log(this.state)
        //this.props.suscribeCallback(values)
    }

    inputGenerator(field, prefix) {
        const { key, value } = field;
        const { type } = value;
        const textValidate = FormGenerator.textValidate;
        const newKey = `${prefix}${key}`
        let element = null;
        const createInput = FormGenerator.createInput;

        switch (true) {
            case new RegExp(INPUTTYPES.TEXT.join("|"), "i").test(type):
                value.type = "text";
                element = createInput(newKey, value, textValidate)
                break;
            case new RegExp(INPUTTYPES.NUMBER.join("|"), "i").test(type):
                value.type = "number";
                element = createInput(newKey, value, textValidate)
                break;
            case new RegExp(INPUTTYPES.SELECT.join("|"), "i").test(type):
                break;
            default:
                log.error("DATA NOT ITENDIFIED TYPE:" + type, key, value);
                break;
        }
        return element;
    }

    render() {
        let fields = this.props.fields;
        let { prefix } = this.props;
        prefix = prefix ? prefix + CONCAT_ID_BASES : ''
        const { inputGenerator, onSubmit } = this;

        return (
            <Form
                onSubmit={onSubmit}
                initialValues={this.state.data}
                render={({ values }) => {
                    return <div className="form-row">
                        {fields.map((field) => {
                            return inputGenerator(field, prefix);
                        })}
                        <pre>{JSON.stringify(values, 0, 2)}</pre>
                    </div>
                }} />
        )
    }
}

export default FormGenerator;

并这样称呼它:

{
                detalles ? (() => {
                  return <FormGenerator
                    suscribeCallback={this.formDataChange}
                    prefix={this.props.prefix}
                    fields={detalles} />
                })() : null
              }

但现在的问题是,我需要在values外部阅读,<Form/>这样我才能在它的父级中阅读它。

如果我包含一个回调并将其扔到渲染方法this.props.suscribeCallback(values)中,它会尝试调用它,它会导致站点崩溃。当然这不是一个有效的解决方案,但我不知道如何解决它。

我对 Reactjs 有点陌生,所以如果这是初学者的错误,请道歉

标签: reactjsecmascript-6react-final-form

解决方案


如果您需要表单之外的表单数据,我建议您使用类似Redux Example中探索的模式,其中FormStateToRedux组件正在侦听表单状态的变化并将其发送......某处。不一定是 Redux。


推荐阅读