我正在使用手工制作的表单生成器,并使用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/>
,以便可以在其父目录中阅读。
如果我包含一个回叫并将其扔到render方法this.props.suscribeCallback(values)
中,它将尝试对其进行过多调用,以致使网站崩溃。当然,这不是有效的解决方案,但我不知道如何解决。
我是Reactjs的新手,如果这是初学者的错误,请表示歉意
答案 0 :(得分:0)
假设您有一个名为SignUp
的父组件,并且有一个名为SignUpForm
的子组件,一个好的解决方案是将所有表单信息都包含在该子组件中,然后调用{{1}完成后,在父级中起作用。但是,如果您真的想操纵父母的状态进入您的孩子,它将看起来像这样:
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)} />
)
}
}
事件都会更新父级上控件的值。
答案 1 :(得分:0)
如果您需要表单之外的表单数据,我建议使用类似Redux Example中探索的模式的工具,其中FormStateToRedux
组件正在侦听表单状态的更改并将其发送。 ..某处。不必是Redux。