我有一个显示人员表单(redux-form)的 React 组件(最初由其他人编写)。最近,我将组件更改为 FieldArray(redux-form 的组件)。
我对影响电子邮件字段的类名的电子邮件字段进行了验证(电子邮件格式不正确时为红色,否则为黑色)。当它不是 FieldArray 时它工作得很好,但现在它一次验证所有电子邮件字段,因为
// (in constructor)
this.email = React.createRef();
// (in Field)
ref={props.parent.email}
,即 props.parent.email 是一个全局/静态参考。
例:有两个人。其中一封电子邮件格式不正确,但两封电子邮件均显示为红色。
据我了解,我需要一个动态参考,但这并没有像我尝试的那样工作。
ref={`${person}.email.ref`}
错误是
“函数组件不能有引用。你的意思是使用 React.forwardRef() 吗?”
除了它是一个有效的道具这一事实之外,我没有发现关于 FieldArray 的 forwardRef 有任何帮助。
我的目标是:当用户创建和/或从 Redux 商店加载多个人员时,能够将每封正确格式的电子邮件显示为黑色,并将每封格式不正确的电子邮件显示为红色。
任何帮助是极大的赞赏!
import React from "react";
import { Field, reduxForm, FieldArray } from "redux-form";
import { connect } from "react-redux";
import classNames from 'classnames'
import { MAIL_PATTERN } from "../some_file";
import MoreGeneralComponent from "../some_other_file";
const renderField = ({ input, label, type, options, className, meta: { touched, error }, style, disabled, hidden }) => (
<div style={style}>
<label>{label}</label>
<div>
<input {...input} disabled={disabled ? true : false} hidden={hidden ? true : false} type={type} placeholder={label} className={className} />
</div>
</div>
);
const renderPerson = ({ fields, meta: { error, submitFailed }, ...props }) => {
setTimeout(props.validate(fields));
return (
<ul className="personlist">
{fields.map((person, index) => (
<li key={index} className="person">
<h4>Person #{index + 1}</h4>
<Field
component={renderField}
type="text"
ref={props.parent.email}
className={classNames({invalid: !props.parent.state.validEmail})}
validate={props.parent.validateEmail}
name={`${person}.email`}
label="Email"
key={`${person}.email`}
></Field>
<button type="button" onClick={() => fields.remove(index)}>
Remove
</button>
</li>
))}
{(!(fields.length >= props.max)) && (
<li className="addperson">
<button
type="button"
onClick={() => fields.push({})}
disabled={fields.length >= props.max}
>
Add Person
</button>
{submitFailed && error && <span>{error}</span>}
</li>)}
</ul>
);
};
class Person extends MoreGeneralComponent {
constructor(props) {
super(props);
if (this.state.ready) {
this.max = 4;
this.data = ["email"];
this.email = React.createRef();
}
}
validate = fields => {
if (!fields || !fields.getAll()) {
return;
}
let valid = true;
fields.getAll().forEach(field => {
for (let d of this.data) {
if (!field[d] || field[d].length < 2) {
valid = false;
return;
} else if (d === "email") {
valid = field[d] && MAIL_PATTERN.test(field[d]) ? valid : undefined;
}
}
});
if (valid !== this.state.valid) {
this.setState({
valid: valid
});
}
};
validateEmail = (value) => {
const valid = value && MAIL_PATTERN.test(value) ? value : undefined;
this.setState({validEmail: !!valid});
return valid
}
renderQuestion() {
return (
<div className={style.question}>
<fieldset>
<FieldArray
name="persons"
component={renderPerson}
props={{ max: this.max, validate: this.validate, parent: this }}
rerenderOnEveryChange={true}
/>
</fieldset>
</div>
);
}
}
const mapStateToProps = s => {
const persons = s.persons
var initialValuesPersons = []
persons.map(item => initialValuesPersons.push({
"email": item.email || ""
}))
var initialValues = { "persons": initialValuesPersons}
return {
initialValues,
formdata: s.form
}
}
export default connect(mapStateToProps, null)(reduxForm(
{
form: 'person',
destroyOnUnmount: false,
enableReinitialize: true,
keepDirtyOnReinitialize: true
})(Person))