Как правильно проверить входные значения с помощью React.JS?

StackOverflow https://stackoverflow.com//questions/24019431

Вопрос

У меня есть простая форма.Все компоненты и состояние хранятся в компоненте Страницы.Есть 2 отображаемых заголовка и 3 поля ввода.Предполагается, что первый ввод должен быть текстовым, а второй и третий - целыми числами.Когда пользователь вводит неправильный тип данных, я хочу, чтобы рядом с полем ввода появлялось сообщение об ошибке.Мои вопросы касаются лучших практик в React.JS

Кто решает, что значение является допустимым?Я полагаю, что единственная задача поля ввода - направить значение обратно в компонент, сохраняющий состояние, так означает ли это, что только страница может определить, является ли значение допустимым?

Как мне тогда заставить появиться всплывающее окно?Должна ли страница инициировать новый элемент логического состояния, который будет передан через perp, который сообщит Adaptive_Input о появлении сообщения об ошибке?

JSFiddle

JS:

/**
 * @jsx React.DOM
 */
var Adaptive_Input = React.createClass({ 
    handle_change: function(){
        var new_text = this.refs.input.getDOMNode().value;
        this.props.on_Input_Change(new_text);
    },
    render: function(){
        return (
                <div className='adaptive_placeholder_input_container'>
                    <input 
                        className="adaptive_input"
                        type="text" 
                        required="required" 
                        onChange= {this.handle_change}
                        ref="input"
                    ></input>
                    <label
                        className="adaptive_placeholder"
                        alt={this.props.initial}
                        placeholder={this.props.focused}
                    ></label>
                </div>              
                );
    }
});

var Form = React.createClass({
    render: function(){
        return (
                <form>
                    <Adaptive_Input
                        initial={'Name Input'}
                        focused={'Name Input'}
                        on_Input_Change={this.props.handle_text_input}
                    />
                    <Adaptive_Input
                        initial={'Value 1'}
                        focused={'Value 1'}
                        on_Input_Change={this.props.handle_value_1_input}
                    />
                    <Adaptive_Input
                        initial={'Value 2'}
                        focused={'Value 2'}
                        on_Input_Change={this.props.handle_value_2_input}
                    />
                </form>
                );
    }
});

var Page = React.createClass({
    getInitialState: function(){
        return {
            Name : "No Name",
            Value_1 : '0',
            Value_2 : '0',
            Display_Value: '0'
        };
    },
    handle_text_input: function(new_text){
        this.setState({
                Name: new_text
            });
    },
    handle_value_1_input: function(new_value){
        console.log("===");
        var updated_display = parseInt(new_value) + parseInt(this.state.Value_2);
        updated_display = updated_display.toString();
        this.setState({
                Display_Value: updated_display 
            });
    },
    handle_value_2_input: function(new_value){
        var updated_display = parseInt(this.state.Value_1) + parseInt(new_value);
        updated_display = updated_display.toString();
        this.setState({
                Display_Value: updated_display
            });
    },
    render: function(){
        return(
                <div>
                    <h2>{this.state.Name}</h2>
                    <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>
                    <Form
                        handle_text_input={this.handle_text_input}
                        handle_value_1_input = {this.handle_value_1_input}
                        handle_value_2_input = {this.handle_value_2_input}
                    />
                </div>
        );
    }
});

React.renderComponent(<Page />, document.body);
Это было полезно?

Решение

Во-первых, вот пример того, что я отмечу ниже: http://jsbin.com/rixido/2/edit

Как правильно проверить входные значения с rance.js?

Однако вы хотите. Реагировать для рендеринга модели данных. Модель данных должна знать, что действует или нет. Вы можете использовать магистральные модели, данные JSON, или все, что вы хотите представлять данные, и это состояние ошибки.

Более конкретно:

Реакция в реакции, как правило, агностика к вашим данным. Это для рендеринга и устранения событий.

Правила для следующих действий:

    Элементы
  1. могут изменить свое состояние.
  2. они не могут изменить реквизиты.
  3. Они могут вызывать обратный вызов, который изменит вызов верхнего уровня.
  4. Как решить, должно ли что-то предпоречить или состояние? Рассмотрим это: не будет ли какой-либо часть вашего приложения, кроме текстового поля, чтобы узнать, что введенное значение плохое? Если нет, сделайте его государством. Если да, это должно быть опоры.

    Например, если вы хотите отдельного представления о рендере «У вас есть 2 ошибки на этой странице». Тогда ваша ошибка должна быть известна моделью данных Toplevel.

    Где эта ошибка вжимает?
    Если ваше приложение обрабатывает модели позволителей (например), сама модель будет иметь Validate () метод и свойство ValidateError, которую вы могли бы использовать. Вы можете сделать другие умные объекты, которые могут сделать то же самое. Реагируйте также говорят, попробуйте сохранить репортаж минимум и генерировать остальные данные. Так что, если у вас был валидатор (например, https://github.com/flatiron/Revalidator ), тогда ваши проверки могут проскальзывать и любой Компонент может проверить реквизиты с соответствующей проверкой, чтобы увидеть, действительно ли это.

    Это в значительной степени зависит от вас.

    (я лично с использованием моделей позвоночника и рендеринг их в реагировании. У меня есть оповещение об ошибке Toplevel, что я показываю, если есть ошибка в любом месте, описывая ошибку.)

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

Вы можете использовать npm install --save redux-form

Я пишу простую электронную почту и отправьте форму кнопки, которая проверяет электронную почту и подает форму.С redux-формой, форма по умолчанию работает event.preventdefault () на html onsubmit действие.

import React, {Component} from 'react';
import {reduxForm} from 'redux-form';

class LoginForm extends Component {
  onSubmit(props) {
    //do your submit stuff
  }


  render() {
    const {fields: {email}, handleSubmit} = this.props;

    return (
      <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
        <input type="text" placeholder="Email"
               className={`form-control ${email.touched && email.invalid ? 'has-error' : '' }`}
          {...email}
        />
          <span className="text-help">
            {email.touched ? email.error : ''}
          </span>
        <input type="submit"/>
      </form>
    );
  }
}

function validation(values) {
  const errors = {};
  const emailPattern = /(.+)@(.+){2,}\.(.+){2,}/;
  if (!emailPattern.test(values.email)) {
    errors.email = 'Enter a valid email';
  }

  return errors;
}

LoginForm = reduxForm({
  form: 'LoginForm',
  fields: ['email'],
  validate: validation
}, null, null)(LoginForm);

export default LoginForm;
.

Я написал Эта библиотека которая позволяет обернуть свои элементы формы, и позволяетВы определяете ваши валидаторы в формате: -

<Validation group="myGroup1"
    validators={[
            {
             validator: (val) => !validator.isEmpty(val),
             errorMessage: "Cannot be left empty"
            },...
        }]}>
            <TextField value={this.state.value}
                       className={styles.inputStyles}
                       onChange={
                        (evt)=>{
                          console.log("you have typed: ", evt.target.value);
                        }
                       }/>
</Validation>
.

Ваш jsfiddle больше не работает. Я исправил это: http://jsfiddle.net/tkrotoff/bgc6e/40/2/a > Использование классов реагирования 16 и ES6.

class Adaptive_Input extends React.Component {
  handle_change(e) {
    var new_text = e.currentTarget.value;
    this.props.on_Input_Change(new_text);
  }

  render() {
    return (
      <div className="adaptive_placeholder_input_container">
        <input
          className="adaptive_input"
          type="text"
          required="required"
          onChange={this.handle_change.bind(this)} />
        <label
          className="adaptive_placeholder"
          alt={this.props.initial}
          placeholder={this.props.focused} />
      </div>
    );
  }
}

class Form extends React.Component {
  render() {
    return (
      <form>
        <Adaptive_Input
          initial={'Name Input'}
          focused={'Name Input'}
          on_Input_Change={this.props.handle_text_input} />

        <Adaptive_Input
          initial={'Value 1'}
          focused={'Value 1'}
          on_Input_Change={this.props.handle_value_1_input} />

        <Adaptive_Input
          initial={'Value 2'}
          focused={'Value 2'}
          on_Input_Change={this.props.handle_value_2_input} />
      </form>
    );
  }
}

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

    this.state = {
      Name: 'No Name',
      Value_1: '0',
      Value_2: '0',
      Display_Value: '0'
    };
  }

  handle_text_input(new_text) {
    this.setState({
      Name: new_text
    });
  }

  handle_value_1_input(new_value) {
    new_value = parseInt(new_value);
    var updated_display = new_value + parseInt(this.state.Value_2);
    updated_display = updated_display.toString();
    this.setState({
      Value_1: new_value,
      Display_Value: updated_display
    });
  }

  handle_value_2_input(new_value) {
    new_value = parseInt(new_value);
    var updated_display = parseInt(this.state.Value_1) + new_value;
    updated_display = updated_display.toString();
    this.setState({
      Value_2: new_value,
      Display_Value: updated_display
    });
  }

  render() {
    return(
      <div>
        <h2>{this.state.Name}</h2>
        <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>
        <Form
          handle_text_input={this.handle_text_input.bind(this)}
          handle_value_1_input={this.handle_value_1_input.bind(this)}
          handle_value_2_input={this.handle_value_2_input.bind(this)}
        />
      </div>
    );
  }
}

ReactDOM.render(<Page />, document.getElementById('app'));
.

А теперь тот же код взломал валидацией формы благодаря этой библиотеке: https: / /github.com/tkrotoff/react-form-with-constraints . => http://jsfiddle.net/tkrotoff/k4qa4heg/

 http://jsfiddle.net/tkrotoff/k4qa4heg/

const { FormWithConstraints, FieldFeedbacks, FieldFeedback } = ReactFormWithConstraints;

class Adaptive_Input extends React.Component {
  static contextTypes = {
    form: PropTypes.object.isRequired
  };

  constructor(props) {
    super(props);

    this.state = {
      field: undefined
    };

    this.fieldWillValidate = this.fieldWillValidate.bind(this);
    this.fieldDidValidate = this.fieldDidValidate.bind(this);
  }

  componentWillMount() {
    this.context.form.addFieldWillValidateEventListener(this.fieldWillValidate);
    this.context.form.addFieldDidValidateEventListener(this.fieldDidValidate);
  }

  componentWillUnmount() {
    this.context.form.removeFieldWillValidateEventListener(this.fieldWillValidate);
    this.context.form.removeFieldDidValidateEventListener(this.fieldDidValidate);
  }

  fieldWillValidate(fieldName) {
    if (fieldName === this.props.name) this.setState({field: undefined});
  }

  fieldDidValidate(field) {
    if (field.name === this.props.name) this.setState({field});
  }

  handle_change(e) {
    var new_text = e.currentTarget.value;
    this.props.on_Input_Change(e, new_text);
  }

  render() {
    const { field } = this.state;
    let className = 'adaptive_placeholder_input_container';
    if (field !== undefined) {
      if (field.hasErrors()) className += ' error';
      if (field.hasWarnings()) className += ' warning';
    }

    return (
      <div className={className}>
        <input
          type={this.props.type}
          name={this.props.name}
          className="adaptive_input"
          required
          onChange={this.handle_change.bind(this)} />
        <label
          className="adaptive_placeholder"
          alt={this.props.initial}
          placeholder={this.props.focused} />
      </div>
    );
  }
}

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

    this.state = {
      Name: 'No Name',
      Value_1: '0',
      Value_2: '0',
      Display_Value: '0'
    };
  }

  handle_text_input(e, new_text) {
    this.form.validateFields(e.currentTarget);

    this.setState({
      Name: new_text
    });
  }

  handle_value_1_input(e, new_value) {
    this.form.validateFields(e.currentTarget);

    if (this.form.isValid()) {
      new_value = parseInt(new_value);
      var updated_display = new_value + parseInt(this.state.Value_2);
      updated_display = updated_display.toString();
      this.setState({
        Value_1: new_value,
        Display_Value: updated_display
      });
    }
    else {
      this.setState({
        Display_Value: 'Error'
      });
    }
  }

  handle_value_2_input(e, new_value) {
    this.form.validateFields(e.currentTarget);

    if (this.form.isValid()) {
      new_value = parseInt(new_value);
      var updated_display = parseInt(this.state.Value_1) + new_value;
      updated_display = updated_display.toString();
      this.setState({
        Value_2: new_value,
        Display_Value: updated_display
      });
    }
    else {
      this.setState({
        Display_Value: 'Error'
      });
    }
  }

  render() {
    return(
      <div>
        <h2>Name: {this.state.Name}</h2>
        <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>

        <FormWithConstraints ref={form => this.form = form} noValidate>
          <Adaptive_Input
            type="text"
            name="name_input"
            initial={'Name Input'}
            focused={'Name Input'}
            on_Input_Change={this.handle_text_input.bind(this)} />
          <FieldFeedbacks for="name_input">
            <FieldFeedback when="*" error />
            <FieldFeedback when={value => !/^\w+$/.test(value)} warning>Should only contain alphanumeric characters</FieldFeedback>
          </FieldFeedbacks>

          <Adaptive_Input
            type="number"
            name="value_1_input"
            initial={'Value 1'}
            focused={'Value 1'}
            on_Input_Change={this.handle_value_1_input.bind(this)} />
          <FieldFeedbacks for="value_1_input">
            <FieldFeedback when="*" />
          </FieldFeedbacks>

          <Adaptive_Input
            type="number"
            name="value_2_input"
            initial={'Value 2'}
            focused={'Value 2'}
            on_Input_Change={this.handle_value_2_input.bind(this)} />
          <FieldFeedbacks for="value_2_input">
            <FieldFeedback when="*" />
          </FieldFeedbacks>
        </FormWithConstraints>
      </div>
    );
  }
}

ReactDOM.render(<Form />, document.getElementById('app'));
.

Предлагаемое решение здесь - это взлома, так как я пытался сохранить его рядом с оригинальным jsfiddle. Для правильной проверки формы с ограничениями React-Form-S-ограничений, проверьте https:// github.com/tkrotoff/react-form-with-constraints#xamples

Воспользуйся onChange={this.handleChange.bind(this, "name") способ и value={this.state.fields["name"]} в текстовом поле ввода и ниже этого создайте элемент span, чтобы показать ошибку, смотрите пример ниже.

export default class Form extends Component {

  constructor(){
    super()
    this.state ={
       fields: {
         name:'',
         email: '',
         message: ''
       },
       errors: {},
       disabled : false
    }
  }

  handleValidation(){
       let fields = this.state.fields;
       let errors = {};
       let formIsValid = true;

       if(!fields["name"]){
          formIsValid = false;
          errors["name"] = "Name field cannot be empty";
       }

       if(typeof fields["name"] !== "undefined" && !fields["name"] === false){
          if(!fields["name"].match(/^[a-zA-Z]+$/)){
             formIsValid = false;
             errors["name"] = "Only letters";
          }
       }

       if(!fields["email"]){
          formIsValid = false;
          errors["email"] = "Email field cannot be empty";
       }

       if(typeof fields["email"] !== "undefined" && !fields["email"] === false){
          let lastAtPos = fields["email"].lastIndexOf('@');
          let lastDotPos = fields["email"].lastIndexOf('.');

          if (!(lastAtPos < lastDotPos && lastAtPos > 0 && fields["email"].indexOf('@@') === -1 && lastDotPos > 2 && (fields["email"].length - lastDotPos) > 2)) {
             formIsValid = false;
             errors["email"] = "Email is not valid";
           }
      }

      if(!fields["message"]){
         formIsValid = false;
         errors["message"] = " Message field cannot be empty";
      }

      this.setState({errors: errors});
      return formIsValid;
  }

  handleChange(field, e){
      let fields = this.state.fields;
      fields[field] = e.target.value;
      this.setState({fields});
  }

  handleSubmit(e){
      e.preventDefault();
      if(this.handleValidation()){
          console.log('validation successful')
        }else{
          console.log('validation failed')
        }
  }

  render(){
    return (
      <form onSubmit={this.handleSubmit.bind(this)} method="POST">
          <div className="row">
            <div className="col-25">
                <label htmlFor="name">Name</label>
            </div>
            <div className="col-75">
                <input type="text" placeholder="Enter Name"  refs="name" onChange={this.handleChange.bind(this, "name")} value={this.state.fields["name"]}/>
                <span style={{color: "red"}}>{this.state.errors["name"]}</span>
            </div>
          </div>
          <div className="row">
            <div className="col-25">
              <label htmlFor="exampleInputEmail1">Email address</label>
            </div>
            <div className="col-75">
                <input type="email" placeholder="Enter Email" refs="email" aria-describedby="emailHelp" onChange={this.handleChange.bind(this, "email")} value={this.state.fields["email"]}/>
                <span style={{color: "red"}}>{this.state.errors["email"]}</span>
            </div>
          </div>
          <div className="row">
            <div className="col-25">
                <label htmlFor="message">Message</label>
            </div>
            <div className="col-75">
                <textarea type="text" placeholder="Enter Message" rows="5" refs="message" onChange={this.handleChange.bind(this, "message")} value={this.state.fields["message"]}></textarea>
                <span style={{color: "red"}}>{this.state.errors["message"]}</span>
            </div>
          </div>
          <div className="row">
            <button type="submit" disabled={this.state.disabled}>{this.state.disabled ? 'Sending...' : 'Send'}</button>
          </div>
      </form>
    )
  }
}

Я недавно провел неделю, изучая много решений, чтобы подтвердить мои формы в приложении.Я начал со всех самых уставившихся, но я не мог найти тех, кто работал, как я ожидал.Через несколько дней я стал довольно разочарован, пока не нашел очень новый и удивительный плагин: https://github.com/kettanaito/react-advanced-form

Разработчик очень отзывчивый и его решение, после моего исследования, заслуга, чтобы стать самым взглядом на одну перспективу.Я надеюсь, что это может помочь, и вы оцените.

еще один идет по той же проблеме - form-container на NPM

Я использовал Redux-Form и Formik в прошлом, и недавно отреагировал вводимый крюк, и я построил пользовательский крючок для него.Пожалуйста, проверьте его и посмотрите, сделают ли он проверкой формы намного проще.

github: https://github.com/bluebill1049/react-hook-form

сайт: http://react-hook-form.now.sh P >.

С таким подходом вас тоже больше не выполняют контролируемый вход.

Пример ниже:

import React from 'react'
import useForm from 'react-hook-form'

function App() {
  const { register, handleSubmit, errors } = useForm() // initialise the hook
  const onSubmit = (data) => { console.log(data) } // callback when validation pass

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstname" ref={register} /> {/* register an input */}

      <input name="lastname" ref={register({ required: true })} /> {/* apply required validation */}
      {errors.lastname && 'Last name is required.'} {/* error message */}

      <input name="age" ref={register({ pattern: /\d+/ })} /> {/* apply a Refex validation */}
      {errors.age && 'Please enter number for age.'} {/* error message */}

      <input type="submit" />
    </form>
  )
}
.

Иногда вы можете иметь несколько полей с аналогичной проверкой в вашем приложении.В таком случае я рекомендую создать общий поле компонента, где вы сохраняете эту проверку.

Например, давайте предположим, что у вас есть обязательный ввод текста в нескольких местах в вашем приложении.Вы можете создать компонент TextInput:

constructor(props) {
    super(props); 
    this.state = {
        touched: false, error: '', class: '', value: ''
    }
}

onValueChanged = (event) => {
    let [error, validClass, value] = ["", "", event.target.value];

    [error, validClass] = (!value && this.props.required) ? 
        ["Value cannot be empty", "is-invalid"] : ["", "is-valid"]

    this.props.onChange({value: value, error: error});

    this.setState({
        touched: true,
        error: error,
        class: validClass,
        value: value
    })
}

render() {
    return (
        <div>
            <input type="text"
                value={this.props.value}
                onChange={this.onValueChanged}
                className={"form-control " + this.state.class}
                id="{this.props.id}"
                placeholder={this.props.placeholder} />
            {this.state.error ?
                <div className="invalid-feedback">
                    {this.state.error}
                </div> : null
            }
        </div>
    )
}
.

, а затем вы можете использовать такой компонент в любом месте вашего приложения:

constructor(props) {
    super(props);
    this.state = {
        user: {firstName: '', lastName: ''},
        formState: {
            firstName: { error: '' },
            lastName: { error: '' }
        }
    }
}

onFirstNameChange = (model) => {
    let user = this.state.user;
    user.firstName = model.value;

    this.setState({
        user: user,
        formState: {...this.state.formState, firstName: { error: model.error }}
    })
}

onLastNameChange = (model) => {
    let user = this.state.user;
    user.lastName = model.value;

    this.setState({
        user: user,
        formState: {...this.state.formState, lastName: { error: model.error }}
    })
}


onSubmit = (e) => {
   // submit logic
}


render() {
    return (
        <form onSubmit={this.onSubmit}>
            <TextInput id="input_firstName"
                value={this.state.user.firstName}
                onChange={this.onFirstNameChange}
                required = {true}
                placeholder="First name" />

            <TextInput id="input_lastName"
                value={this.state.user.lastName}
                onChange={this.onLastNameChange}
                required = {true}
                placeholder="Last name" />

            {this.state.formState.firstName.error || this.state.formState.lastName.error ?
                <button type="submit" disabled className="btn btn-primary margin-left disabled">Save</button>
                : <button type="submit" className="btn btn-primary margin-left">Save</button>
            }

        </form>
    )
}
.

Преимущества:

    .
  • Вы не повторяете свою логику проверки
  • Меньше кода в ваших формах - это более читаемый
  • Другая общая логика ввода может быть сохранена в компоненте
  • Вы следуете правилу реагирования, что компонент должен быть максимально глупым, насколько это возможно

ref. https://webfellas.tech/#/article/5

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top