【问题标题】:How to prevent repeating code of form validation如何防止表单验证的重复代码
【发布时间】:2018-11-03 15:34:58
【问题描述】:

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

我的程序可以运行,但我不喜欢在两个地方重复验证代码: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')
)

【问题讨论】:

    标签: forms reactjs validation jsx


    【解决方案1】:

    你可以提取一个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 这样的库变得方便的地方。

    更新

    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>
        );
      }
    }
    

    【讨论】:

    • 谢谢,我会用你的例子来提取组件。这真的很有用。但是我关于防止使用验证规则重复代码的问题仍然存在。我该如何解决这个问题?
    • @Herasimenak 我已经更新了答案,请看一下
    【解决方案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"));
    

    【讨论】:

    • 在你的例子中,只有点击“发送”按钮后才会检查数据,但输入数据时不会显示错误信息
    • @EvgenyTimoshenko 我认为由于数据验证代码仅在 validateData func 中比将它放在 handleSubmit 和 ErrorOutput 组件中更好。
    • @Herasimenak 我理解,也许我们也应该在输入元素上引发 onChange 事件时验证数据,但我不知道它是否可行。
    猜你喜欢
    • 1970-01-01
    • 2012-10-03
    • 2019-06-18
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    相关资源
    最近更新 更多