Как предотвратить повторение кода проверки формы

Я создал форму для нескольких входов, где конкретные входные данные должны быть проверены во время ввода данных и еще раз для всех данных непосредственно перед отправкой формы на бэкэнд. Условия подачи: все поля обязательны, данные действительны.

Моя программа работает, но мне не нравится, что я повторяю код проверки в 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')
)
JS - События опций формы
JS - События опций формы
В продолжение предыдущей статьи CSS - стили, связанные с вводом формы , в этой статье мы будем использовать JS для взаимодействия с формами, на этот...
CSS - Стили, связанные с вводом формы
CSS - Стили, связанные с вводом формы
Общими стилями ввода для форм являются Input (включая Text, Radio, checkbox), Select и Textarea, из которых Input относительно прост, поэтому в этой...
Создание многостраничной формы заявления о приеме на работу с помощью Angular
Создание многостраничной формы заявления о приеме на работу с помощью Angular
Наличие на корпоративном сайте форм заявлений о приеме на работу, или "трудовых анкет", экономит время и деньги как для соискателей, так и для...
2
0
311
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>
    )
  }

здесь становятся удобными такие библиотеки, как окончательная форма реакции и редукционная форма.

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

Спасибо, я воспользуюсь вашим примером для извлечения компонентов. Это действительно полезно. Но мой вопрос о предотвращении повторения кода с правилами проверки все еще открыт. Как я могу решить эту проблему?

Kate Herasimenak 24.05.2018 16:32

@Herasimenak Я обновил ответ, пожалуйста, посмотрите

Evgeny Timoshenko 24.05.2018 22:24
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"));

В вашем примере данные проверяются только после того, как вы нажмете кнопку «отправить», но сообщение об ошибке не отображается, когда вы вводите данные.

Kate Herasimenak 24.05.2018 15:56

@EvgenyTimoshenko Я думаю, поскольку код проверки данных находится только в функции validateData, это лучше, чем помещать его в компонент handleSubmit и ErrorOutput.

N. Solomon 24.05.2018 17:28

@Herasimenak Я понимаю, возможно, нам также следует проверять данные, когда событие onChange возникает в элементе ввода, но я не знаю, жизнеспособно ли это.

N. Solomon 24.05.2018 17:34

Другие вопросы по теме