2

我为多个输入创建了表单,其中特定的输入数据应在数据输入时验证,并在将表单提交到后端之前再次验证所有数据。
提交条件:所有字段为必填项且数据有效。

我的程序有效,但我不喜欢我在两个地方重复验证代码:在 ErrorOutput 和 hadleSubmit 中。
在 ErrorOutput 中,我检查数据,并在必要时显示错误消息。
在handleSubmit 中,我只检查数据而不显示错误消息,如果所有数据都有效,我确认提交。

如何改进我的示例以防止重复此代码,但数据验证也是在数据输入时和提交之前?

import React from 'react'
import { render } from 'react-dom'

const ErrorOutput = props => {
  let name = props.name
  let inputValue = props.case
  let submit = props.submit
  // Data validation
  if (name === 'firstName') {
    if (!inputValue.match(/^[a-zA-Z]+$/) && inputValue.length > 0) {
        return <span>Letters only</span>
      } else if (submit && inputValue.length === 0) {
        return <span>Required</span>
      }
    return <span></span>
  }
  if (name === 'telNo') {
    if(!inputValue.match(/^[0-9]+$/) && inputValue.length > 0) {
        return <span>Numbers only</span>
      } else if (submit && inputValue.length === 0) {
        return <span>Required</span>
      }
    return <span></span>
  }
}

class App extends React.Component {
  constructor(props){
    super(props)

    this.state = {
      firstName: '',
      telNo: '',
      submit: false
    }
  }

  handleSubmit(e){
    e.preventDefault()
    let submit = true
    let error = true
    const { firstName, telNo } = this.state
    this.setState ({submit: submit})

    // Repeat the data validation before submission
    if (firstName === '' || !firstName.match(/^[a-zA-Z]+$/)) {
      error = true
    } else if (telNo === '' || !telNo.match(/^[0-9]+$/)) {
      error = true
    } else {
      error = false
    }

    // Submited if all data is valid
    if (!error) {
      // send data
      return alert('Success!')
    }
  }

  handleValidation(e) {    
    this.setState({
      [e.target.name]: e.target.value 
    })  
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit.bind(this)}>
        <div>
          <label>
            First name:
          </label>
          <input
            type='text'
            name ='firstName'
            value = {this.state.firstName}
            onChange = {this.handleValidation.bind(this)}
          />
          <ErrorOutput case={this.state.firstName} name={'firstName'} submit = {this.state.submit} />
        </div>
        <div>
          <label>
            Phone number:
          </label>
          <input
            type='tel'
            name ='telNo'
            value = {this.state.telNo}
            onChange = {this.handleValidation.bind(this)}
          />
          <ErrorOutput case={this.state.telNo} name={'telNo'} submit = {this.state.submit} />
        </div>
        <button>
          Submit
        </button> 
      </form>
    )
  }
}

render(
  <App />,
  document.getElementById('root')
)
4

2 回答 2

2

您可以提取一个FormItem组件:

class FormItem extends React.Component {
  render() {
    return (
      <div>
        <label>
          {this.props.label}
        </label>
        <input
          {...this.props.input}
        />
        <ErrorOutput 
          case={this.props.input.value} 
          name={this.props.input.name} 
          submit={this.props.onSubmit} 
        />
      </div>
    );
  }
}

并将其用于您的App

render() {
    return (
      <form onSubmit={this.handleSubmit.bind(this)}>
        <FormItem label='First name:' input={{
          type: 'text'
            name: 'firstName'
            value: this.state.firstName,
            onChange: this.handleValidation.bind(this)
          }} 
          onSubmit={this.state.submit}
        />
        <FormItem label='Phone number:' input={{
          type:'tel'
            name :'telNo'
            value : {this.state.telNo}
            onChange : {this.handleValidation.bind(this)}
          }} 
          onSubmit={this.state.submit}
        />
        <button>
          Submit
        </button> 
      </form>
    )
  }

这就是react-final-formredux-form等库变得方便的地方。

UPD

ErrorOutput组件不应该验证任何东西,它不是组件的责任。相反,您可以在输入模糊事件和提交之前验证您的值:

class App extends React.Component {
  constructor(props){
    super(props)

    this.state = {
      firstName: '',
      telNo: '',
      submit: false,
      errors: {},
      invalid: false,
    }
  }

  handleSubmit(e){
    e.preventDefault()
    if (this.validate()) {
      // handle error
    } else {
      // submit
    }
  }

  validate = () => {
    const { firstName, telNo } = this.state
    const errors = {}
    let invalid = false;
    if (firstName === '' || !firstName.match(/^[a-zA-Z]+$/)) {
      errors.firstName = 'first name is required'
      invalid = true;
    } else if (telNo === '' || !telNo.match(/^[0-9]+$/)) {
      telNo.telNo = 'telNo is required'
      invalid = true;
    }
    this.setState({
      invalid,
      errors,
    })
    return invalid;
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit.bind(this)}>
        <FormItem label='First name:' input={{
            type: 'text',
            name: 'firstName',
            value: this.state.firstName,
            onChange: e => this.setState({ firstName: e.target.value }),
            onBlur: () => this.validate(),
          }} 
        />
        <FormItem label='Phone number:' input={{
            type: 'tel',
            name: 'telNo',
            value: this.state.telNo,
            onChange: e => this.setState({ telNo: e.target.value }),
            onBlur: () => this.validate(),
          }} 
        />
        <button>
          Submit
        </button> 
      </form>
    )
  }
}

和 FormItem 和 ErrorOutput:

const ErrorOutput = ({ error }) => <span>{error}</span>

class FormItem extends React.Component {
  render() {
    return (
      <div>
        <label>
          {this.props.label}
        </label>
        <input
          {...this.props.input}
        />
        {this.props.error && <ErrorOutput error={this.props.error} />}
      </div>
    );
  }
}
于 2018-05-24T12:06:06.670 回答
2
const ErrorOutput = ({ errorText }) => <span>{errorText}</span>;

class App extends React.Component {
constructor(props) {
    super(props);

    this.state = {
    firstName: "",
    telNo: "",
    submit: false,
    errors: {} //Add errors object to the state.
    };
}

handleSubmit(e) {
    e.preventDefault();
    const errors = this.validateData();

    if (Object.keys(errors).length === 0) {
       alert("Success");
    }
    //else errors exist
    this.setState({ errors });
}

validateData = () => {
    let errors = {};
    const { firstName, telNo } = this.state; // read the values to validate

    if (firstName.length === 0) {
    errors.firstName = "Required";
    } else if (firstName.length > 0 && !firstName.match(/^[a-zA-Z]+$/)) {
    errors.firstName = "Letters only";
    }

    if (telNo.length === 0) {
    errors.telNo = "Required";
    } else if (telNo.length > 0 && !telNo.match(/^[0-9]+$/)) {
    errors.telNo = "Numbers only";
    }

    return errors;
};

handleValidation(e) {
    this.setState({
    [e.target.name]: e.target.value
    });
}

render() {
    const { errors } = this.state; // read errors from the state
    return (
    <form onSubmit={this.handleSubmit.bind(this)}>
        <div>
        <label>First name:</label>
        <input
            type="text"
            name="firstName"
            value={this.state.firstName}
            onChange={this.handleValidation.bind(this)}
        />
        {errors.firstName && <ErrorOutput errorText={errors.firstName} />}
        </div>
        <div>
        <label>Phone number:</label>
        <input
            type="tel"
            name="telNo"
            value={this.state.telNo}
            onChange={this.handleValidation.bind(this)}
        />
        {errors.telNo && <ErrorOutput errorText={errors.telNo} />}
        </div>
        <button>Submit</button>
    </form>
    );
}
}

render(<App />, document.getElementById("root"));
于 2018-05-24T13:17:26.303 回答