2
\$\begingroup\$

I need to validate multiple input fields using React. I am using a simple if-else block for each input field but I would like to optimize my code and make it better. I feel there can be a better way to validate multiple input fields.

  validateForm = () => {
    const {
      firstName, lastName, mobileNo, city, empType, salary
    } = this.state;

    if (firstName !== '') {
      this.setState({
        firstNameMsg: '',
        validFirstName: false
      });
    } else {
      this.setState({
        firstNameMsg: 'Please enter a vaild first name.',
        validFirstName: true
      });
    }
    if (lastName !== '') {
      this.setState({
        lastNameMsg: '',
        validLastName: false
      });
    } else {
      this.setState({
        lastNameMsg: 'Please enter a vaild last name.',
        validLastName: true
      });
    }

    if (mobileNo.match(/^(\+\d{1,3}[- ]?)?\d{10}$/) && !(mobileNo.match(/0{5,}/))) {
      this.setState({
        mobileNoMsg: '',
        validMobileNo: false
      });
    } else {
      this.setState({
        mobileNoMsg: 'Please enter a vaild mobile number.',
        validMobileNo: true
      });
    }

    if (city !== '') {
      this.setState({
        cityMsg: '',
        validCity: false
      });
    } else {
      this.setState({
        cityMsg: 'Please enter a vaild city.',
        validCity: true
      });
    }

    if (empType !== 'Self-Employed') {
      this.setState({
        empTypeMsg: '',
        validEmpType: false
      });
    } else {
      this.setState({
        empTypeMsg: 'Some msg',
        validEmpType: true
      });
    }

    if (salary !== '') {
      this.setState({
        salaryMsg: '',
        validSalary: false
      });
    } else {
      this.setState({
        salaryMsg: 'Please enter a vaild salary.',
        validSalary: true
      });
    }
  }
\$\endgroup\$
3
  • \$\begingroup\$ For completeness, can you include the code for setState() as well? \$\endgroup\$ Feb 28, 2019 at 15:02
  • \$\begingroup\$ @200_success setState() is native to react \$\endgroup\$
    – Taki
    Feb 28, 2019 at 23:18
  • \$\begingroup\$ Honestly, I would look at using a framework like Yup for doing form validation. \$\endgroup\$
    – dwjohnston
    Nov 28, 2019 at 23:47

1 Answer 1

1
\$\begingroup\$

Validation is so common that I recommend generalizing it a little bit (not too much though, there are too many special cases).

One way is to create validations, schema, and data separate from each other. For example:

const validators = {
    required: (config, value) => value !== '',
    mobileNo: (config, value) => value.match(/^(\+\d{1,3}[- ]?)?\d{10}$/) && !(value.match(/0{5,}/)),
    equal: (config, value) => value === config.value
}

const validate = (data, schema) => {
    const messages = {}

    for(let [name, rules] of Object.entries(schema)){
        for(let rule of rules){
            if(!validators[rule.type](rule, data[name])){
                if(!messages.hasOwnProperty(name)) messages[name] = []
                messages[name].push(rule.msg)
            }
        }
    }

    return messages
}

const schema = {
    firstName: [{type: 'required', msg: 'Please enter a valid first name.'}],
    lastName: [{type: 'required', msg: 'Please enter a valid last name.'}],
    mobileNo: [{type: 'required', msg: 'Please enter a mobile number'}, {type: 'mobileNo', msg: 'Please enter a valid mobile number.'}],
    city: [{type: 'required', msg: 'Please enter a vaild city.'}],
    empType: [{type: 'equal', value: 'Self-Employed', msg: 'Some msg'}],
    salary: [{type: 'required', msg: 'Please enter a vaild salary.'}],
}

// In react component
validateForm(){
    const validationMessages = validate(this.state.data, schema)
    this.setState({validationMessages})
}

You can take this much further by adding templated validation messages, and fancy rules of all sorts. But I recommend keeping it simple. You can make multiple variants of the validate function for different needs as they come.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.