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\$
  • \$\begingroup\$ For completeness, can you include the code for setState() as well? \$\endgroup\$ – 200_success Feb 28 at 15:02
  • \$\begingroup\$ @200_success setState() is native to react \$\endgroup\$ – Taki Feb 28 at 23:18
0
\$\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\$
  • \$\begingroup\$ Thanks a lot, @Magnus \$\endgroup\$ – anup Mar 18 at 7:43

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.