Проверка формы с помощью Semantic-UI-React

Я использую официальные компоненты Semantic UI React для создания веб-приложения. У меня есть форма на моей странице регистрации, которая содержит поле электронной почты, поле пароля и поле подтверждения пароля.

import {Component} from 'react';
import {Button, Form, Message} from 'semantic-ui-react';
import {signUp} from '../../actions/auth';

class SignUp extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleSubmit(e, {formData}) {
        e.preventDefault();

        //
        // Potentially need to manually validate fields here?
        //

        // Send a POST request to the server with the formData
        this.props.dispatch(signUp(formData)).then(({isAuthenticated}) => {
            if (isAuthenticated) {
                // Redirect to the home page if the user is authenticated
                this.props.router.push('/');
            }
        }
    }
    render() {
        const {err} = this.props;

        return (
            <Form onSubmit={this.handleSubmit} error={Boolean(err)}>
                <Form.Input label="Email" name="email" type="text"/>
                <Form.Input label="Password" name="password" type="password"/>
                <Form.Input label="Confirm Password" name="confirmPassword" type="password"/>

                {err &&
                    <Message header="Error" content={err.message} error/>
                }

                <Button size="huge" type="submit" primary>Sign Up</Button>
            </Form>
        );
    }
}

Теперь я привык к регулярной библиотеке семантического UI, которая имеет аддон для проверки формы. Обычно я определял бы правила, подобные этому, в отдельном файле JavaScript

$('.ui.form').form({
    fields: {
        email: {
            identifier: 'email',
            rules: [{
                type: 'empty',
                prompt: 'Please enter your email address'
            }, {
                type: 'regExp',
                value: "[a-z0-9!#$%&'*+/=?^_'{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_'{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
                prompt: 'Please enter a valid email address'
            }]
        },
        password: {
            identifier: 'password',
            rules: [{
                type: 'empty',
                prompt: 'Please enter your password'
            }, {
                type: 'minLength[8]',
                prompt: 'Your password must be at least {ruleValue} characters'
            }]
        },
        confirmPassword: {
            identifier: 'confirmPassword',
            rules: [{
                type: 'match[password]',
                prompt: 'The password you provided does not match'
            }]
        }
    }
});

Есть ли аналогичный метод с использованием компонентов Semantic UI React для проверки формы? Я просмотрел документацию без каких-либо успехов, и, похоже, нет примеров проверки с использованием этой библиотеки Semantic UI React.

Нужно ли вместо этого вручную проверять каждое поле в функции handleSubmit? Каков наилучший способ решить эту проблему? Спасибо за помощь!

Ответ 1

По большей части вам необходимо проверить формы вручную. Тем не менее, RSUI включает в себя несколько инструментов, чтобы сделать вещи немного проще, в частности, <Form.Input> об ошибках в <Form> и <Form.Input>

Вот пример формы, которую я собрал недавно. Он может использовать немного рефакторинга, но в основном он работает, привязывая каждый вход к состоянию с помощью функции onChange() и передавая обратный вызов функции отправки, которая контролирует видимость экрана загрузки и "Успех". Спасибо за отправку "часть формы.

export default class MeetingFormModal extends Component {

  constructor(props) {
    super(props)

    this.state = {
      firstName: '',
      lastName: '',
      email: '',
      location: '',
      firstNameError: false,
      lastNameError: false,
      emailError: false,
      locationError: false,
      formError: false,
      errorMessage: 'Please complete all required fields.',
      complete: false,
      modalOpen: false
    }

    this.submitMeetingForm = this.submitMeetingForm.bind(this);
    this.successCallback = this.successCallback.bind(this);
  }


  successCallback() {
    this.setState({
      complete: true
    })
    setTimeout( () => {this.setState({modalOpen: false})}, 5000);
    this.props.hideLoading();
  }

  handleClose = () => this.setState({ modalOpen: false })
  handleOpen = () => this.setState({ modalOpen: true })

  submitMeetingForm() {

    let error = false;

    if (this.state.studentFirstName === '') {
      this.setState({firstNameError: true})
      error = true
    } else {
      this.setState({firstNameError: false})
      error = false
    }
    if (this.state.studentLastName === '') {
      this.setState({lastNameError: true})
      error = true
    } else {
      this.setState({lastNameError: false})
      error = false
    }
    if (this.state.email === '') {
      this.setState({emailError: true})
      error = true
    } else {
      this.setState({emailError: false})
      error = false
    }
    if (this.state.location === '') {
      this.setState({locationError: true})
      error = true
    } else {
      this.setState({locationError: false})
      error = false
    }

    if (error) {
      this.setState({formError: true})
      return
    } else {
      this.setState({formError: false})
    }


    let meeting = {
      first_name: this.state.firstName,
      last_name: this.state.lastName,
      email: this.state.email,
      location: this.state.location,

    this.props.createMeeting(meeting, this.successCallback)
    this.props.showLoading();
  }

  capitalize(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  }

  render() {
    return(
      <Modal
        trigger={<Button onClick={this.handleOpen} basic color='blue'>Schedule Now</Button>}
        open={this.state.modalOpen}
        onClose={this.handleClose}
        closeIcon={true}
      >
        <Modal.Header>Schedule Your Interview</Modal.Header>
        <Modal.Content>
          {!this.state.complete ?
          <Modal.Description>
            <Form error={this.state.formError}>
              <Form.Group widths='equal'>
                <Form.Field>
                  <Form.Input required={true} onChange={(e) => this.setState({firstName: e.target.value})} label='First Name' placeholder="First Name..." error={this.state.firstNameError}/>
                </Form.Field>
                <Form.Field>
                  <Form.Input required={true} onChange={(e) => this.setState({lastName: e.target.value})} label='Last Name' placeholder="Last Name..." error={this.state.lastNameError}/>
                </Form.Field>
              </Form.Group>
              <Form.Field >
                <Form.Input required={true} onChange={(e) => this.setState({email: e.target.value})} label='Email' placeholder="Email..." error={this.state.emailError}/>
              </Form.Field>
              <Form.Field>
                <Form.Input required={true} onChange={(e) => this.setState({location: e.target.value})} label='Location' placeholder='City, State/Province, Country...' error={this.state.locationError}/>
              </Form.Field>
            </Form>
          </Modal.Description>
          : 
            <div className='modal-complete'>
              <Image src='/images/check.png' />
              <p>Thanks for scheduling a meeting, {this.capitalize(this.state.name)}. We've received your information and we'll be in touch shortly.</p>
            </div>
          }
        </Modal.Content>
        {!this.state.complete ?
        <Modal.Actions>
          <Button color='red' onClick={this.handleClose}>Close</Button>
          <Button positive icon='checkmark' labelPosition='right' content="Submit" onClick={this.submitMeetingForm} />
        </Modal.Actions>
        : null }
      </Modal>
    )
  }
}

Надеюсь, это поможет!

Ответ 2

Нужно ли вместо этого вручную проверять каждое поле в функции handleSubmit?

Печально, но верно. В настоящее время SUIR не имеет проверки формы. Тем не менее, вы можете использовать HOC для работы с такими формами, как redux-form.

Ответ 3

Вы можете использовать плагин для проверки. Название плагина: formsy-semantic-ui-react

Ответ 4

Код ниже по существу устанавливает состояние для каждого имени компонента и связанного значения. (То есть, состояние может выглядеть как {marketSide: buy, price: 50, number: 9}. Я также вставляю информацию об ошибках форм в состояние, используя преимущества поведения по умолчанию yup, чтобы не проверять поля, которые не упомянуты схемой проверки.,

Важные моменты:

1) Вызов schema.validate(someObjectToValidate, yupProperties), (где someObjectToValidate - просто this.state) должен передать {abortEarly: false} в качестве объекта свойств, чтобы переопределить поведение по умолчанию yups, чтобы остановить проверку, если одна ошибка имеет был обнаружен, так как наш компонент сообщения формы отображает все ошибки для пользователя.

2) Если проверка yup не удалась, yup выдает исключение, поэтому мы перехватываем исключение и собираем информацию об интересующей нас информации, и обновляем наше состояние этой ошибкой.

3) Мы должны использовать "форму обратного вызова" this.setState(...), так как setState является асинхронным, поэтому проверка объекта состояния происходит только после обновления состояния.

4) если проверка прошла успешно, мы очищаем наши ошибки и массивы errorPath.

5) Это быстрое решение, я проверяю массив errorPaths несколько раз на каждом рендере. Было бы лучше хранить errorPath и информацию об ошибках в объекте json, снабженном именем компонента, а не в двух массивах, чтобы улучшить текущее решение (2 массива * N полей * N потенциальных ошибок = O (2n ^ 2) спектакль.

6) Не <Form.Field control={Radio}> внимания на длинную <Form.Field control={Radio}> стиля <Form.Field control={Radio}> ', вы можете использовать более короткий стиль <Input>, <Button>, <Radio>, т.д. Этот синтаксис не имеет ничего общего с проверкой. Также игнорируйте divs.

import React, { Component } from 'react'
import { Button, Checkbox, Form, Input, Radio, Select, Message,  Label } from 'semantic-ui-react'
import * as yup from 'yup';


const options = [
  { text: 'buy', value: 'buy' },
  { text: 'sell', value: 'sell' },
]

class OrderEntryV3 extends Component {
  state = {
      errorPaths:[],
      errors:[]
  }

  constructor(props){
      super(props);
  }


  schema = yup.object().shape({
    quantity: yup.number().required().positive().integer(),
    price:  yup.number().required().positive(),
    marketSide: yup.string().required(),
    orderType : yup.string().required()
  });



  handleChange = (e, component) => {
      this.setState({[component.name]:component.value}, ()=>this.schema.validate(this.state, {abortEarly:false})
         .then(valid=>this.setState({errorPaths:[], errors:[]})) //called if the entire form is valid
         .catch(err=>this.setState({errors:err.errors, errorPaths: err.inner.map(i=>i.path) }))) //called if any field is invalid
    };


  render() {

    return (
<div id="oeform-content">
    <div id="oeform-left">
      <Form>
          <Form.Field  error={this.state.errorPaths.includes('marketSide')} name="marketSide" control={Select} label='Market side' options={options} placeholder='market side' onChange={this.handleChange}/>
          <Form.Field  error={this.state.errorPaths.includes('quantity')} type='number' name="quantity" control={Input} label='Quantity' placeholder='quantity' onChange={this.handleChange}/>

          <Form.Group>
              <label><b>Order type</b></label>  
        <Form.Field error={this.state.errorPaths.includes('orderType')} >
          <Radio
            label='market'
            name='orderType'
            value='market'
            checked={this.state.orderType === 'market'}
            onChange={this.handleChange}
          />
        </Form.Field>
        <Form.Field error={this.state.errorPaths.includes('orderType')}>
          <Radio
            label='limit'
            name='orderType'
            value='limit'
            checked={this.state.orderType === 'limit'}
            onChange={this.handleChange}
          />
        </Form.Field>
    </Form.Group>
        <Form.Field error={this.state.errorPaths.includes('price')} name='price' control={Input} type='number' label='Price' placeholder='price' onChange={this.handleChange}/>
        <Form.Field control={Button} disabled={!!this.state.errors.length}>Submit</Form.Field>
        <Message visible={!!this.state.errors.length} warning
        header='Please correct the following issues: '
        list={this.state.errors}/>
      </Form>
    </div>
    <div id="oeform-right">
        <p>{JSON.stringify(this.state)}</p>
    </div>
</div>
    )
  }
}

export default OrderEntryV3

Ответ 5

У нас даже есть лучший вариант, хотя и не обеспечивают семантическим-интерфейс реагирует → Formik + Йуп
Formik: помогает в управлении состоянием формы Yup: помогает в проверке этого состояния

У меня есть ниже компонент, который в основном представляет собой форму редактирования, созданную с использованием semantic-ui-реагировать.

import React, { Component } from "react";
import { Button, Form, Modal, Message, Divider } from "semantic-ui-react";
import { Formik } from "formik";
import * as yup from "yup";


class EditAboutGrid extends Component {

  render() {
    const {
      userBasic,
      editBasicModal,
      closeModal
    } = this.props;

    return (
      <Formik
        initialValues={{
          firstName: userBasic.firstName,
          lastName: userBasic.lastName,
          bio: userBasic.bio,
        }}
        validationSchema={yup.object().shape({
          firstName: yup
            .string()
            .required("Name cannot be empty"),
          lastName: yup
            .string()
            .required("Name cannot be empty"),
          bio: yup
            .string()
            .max(1000, "Maximum characters exceed 1000")
            .nullable()
        })}
        onSubmit={(values, actions) => {
          //do your stuff here like api calls
        }}
        render={({
          values,
          errors,
          handleChange,
          handleSubmit,
          isSubmitting,
          dirty,
          setFieldValue
        }) => (
          <Modal open={editBasicModal} size="small">
            <Modal.Header>Your basic details</Modal.Header>
            <Modal.Content scrolling>
              {errors.firstName && <Message error content={errors.firstName} />}
              {errors.lastName && <Message error content={errors.lastName} />}
              {errors.bio && <Message error content={errors.bio} />}

              <Form loading={isSubmitting}>
                <Form.Group inline widths="equal">
                  <Form.Input
                    required
                    label="First Name"
                    fluid
                    type="text"
                    name="firstName"
                    value={values.firstName}
                    onChange={handleChange}
                    error={errors.firstName !== undefined}
                  />
                  <Form.Input
                    required
                    label="Last Name"
                    fluid
                    type="text"
                    name="lastName"
                    value={values.lastName}
                    onChange={handleChange}
                    error={errors.lastName !== undefined}
                  />
                </Form.Group>
                <Form.TextArea
                  label="Bio"
                  type="text"
                  name="bio"
                  value={values.bio}
                  onChange={handleChange}
                  rows={3}
                  error={errors.bio !== undefined}
                />
              </Form>
            </Modal.Content>
            <Modal.Actions open={true}>
              <Button
                onClick={() => (dirty ? closeModal(true) : closeModal(false))}>
                Cancel
              </Button>
              <Button
                primary
                type="submit"
                onClick={handleSubmit}
                loading={isSubmitting}
                disabled={isSubmitting || !isEmpty(errors) || !dirty}>
                Update
              </Button>
            </Modal.Actions>
          </Modal>
        )}
      />
    );
  }
}

И эта форма называется с помощью:

  <EditAboutGrid
    editBasicModal={this.state.editBasicModal}
    userBasic={this.state.user.basic}
    closeModal={this.closeModal}
  />

initialValues - это место, где все начинается. Здесь вы передаете начальные/стандартные значения на входы вашей формы. values (в форме) выберут значение данных из этого значения по умолчанию.

validationSchema - это место, где вся проверка происходит с использованием yup

onSubmit будет вызываться при onSubmit формы.

Обработка формы с помощью Formik + yup очень проста. Я люблю это.