0

我有一个显示人员表单(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))
4

1 回答 1

0

在一位同事的帮助下,我想出了一个只使用 JS 的解决方法(使用 setState 解决)。

    toggleClass = (elementName, addInvalid) => {
        const element = document.getElementsByName(elementName);
        element.forEach(item => {
            // remove class and add later, if necessary
            item.classList.remove("invalid");
            if (addInvalid) {
                item.classList.add("invalid");
            }
        })
    }

    validateEmail = (value, person, form, nameField) => {
        const valid = value && MAIL_PATTERN.test(value) ? value : undefined;
        this.toggleClass(nameField, !valid);
        return valid;
    }
于 2020-04-07T14:47:50.673 回答