Как прочитать данные формы от ребенка к родителю? - PullRequest
1 голос
/ 05 апреля 2019

Я использую созданный вручную генератор форм и использую React Final Form для управления состоянием и данными. Теперь проблема в том, что мне нужно, чтобы компонент вне формы читал данные до того, как они были отправлены, чтобы показать пользователю фактический статус того, как выглядит ввод.

<code>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)}
}} /> ) } } экспорт по умолчанию FormGenerator;

И называя это так:

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

Но теперь проблема в том, что мне нужно прочитать values вне <Form/>, чтобы я мог прочитать его в родительском элементе.

Если я включу обратный вызов и добавлю его в метод рендеринга this.props.suscribeCallback(values), он попытается вызвать его настолько, что это приведет к сбою сайта. Конечно, это неверное решение, но я не знаю, как его решить.

Я новичок в Reactjs, поэтому извиняюсь, если это ошибка новичка

Ответы [ 2 ]

0 голосов
/ 09 апреля 2019

Если вам нужны данные формы вне формы, я бы предложил использовать что-то вроде шаблонов, исследованных в примере Redux, где компонент FormStateToRedux прослушивает изменения состояния формы и отправляет их...где-то.Это не должно быть в Redux.

0 голосов
/ 05 апреля 2019

Допустим, у вас есть родительский компонент с именем SignUp, и у него есть дочерний элемент с именем SignUpForm, хорошее решение будет иметь всю информацию о форме внутри дочернего элемента и просто вызвать функцию submit() в родительском элементе, когда вы сделали. Но если вы действительно хотите манипулировать состоянием родителей в своих детях, это будет выглядеть примерно так:

class SignUp extends Component{
    state = {
        controls:{
            email:{value:'', validation:[/*...*/]},
            pass :{value:'', validation:[/*...*/]
        }
    }

    onChangeText = (key, value) =>{
        this.setState(state =>({
            ...state,
            controls:{
                ...state.controls,
                [key]: {
                    ...state.controls[key],
                    value 
           }
        }))
    }

    render(){
        return(
            <SignUpForm onChangeText={this.onChangeText} />
        )
    }
}

Вот и все на родителя! Мы определили состояние и передали функцию, чтобы ребенок мог обновлять состояние родителя. Теперь о ребенке:

class SignUpForm extends Component{
    render(){
        return(
           <input onChange={e => this.props.onChangeText('email', e.target.value)} />
           <input onChange={e => this.props.onChangeText('pass', e.target.value)} />
        )
    }
}

Теперь каждое событие onChange на дочернем элементе будет обновлять значение элемента управления на родительском элементе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...