使用钩子,React简单验证表单

时间:2020-01-10 22:24:55

标签: reactjs react-hooks

我之前有一个对受控表单的表单验证,并且我正在尝试使用钩子将类组件转换为功能组件。但是我在实现原始的onBlur和onChange方法时遇到了问题。我的原始代码:

import React, {Component} from 'react';
import { Label, Button, Col, Row, FormFeedback, Input, Form } from 'reactstrap';

function SignUp (){
    return(
        <div className="container">
            <div className="row" style={{'padding': '30px 12px 60px 12px'}}>
            <div className="col col-md-8">
                <h4>Inscríbete y crea tu galería de pesonajes!</h4>
            </div>
        </div>
        <div className="row row-content">
            <div className="col col-md-8">
                {<SignUpForm />}
            </div>
        </div>
    </div>
 );
}
class SignUpForm extends Component {

  constructor(props){
      super(props);
  this.state= {
      firstName: '',
      lastName: '',
      email: '',
      username: '',
      pass: '',
      touched:{
        firstName: false,
        lastName: false,
        email: false,
        pass: false,
      }
  }

  this.handleSubmit = this.handleSubmit.bind(this);
  this.handleInput = this.handleInput.bind(this);
  this.handleBlur = this.handleBlur.bind(this);
  }

  handleInput (e) {
    const target = e.target;
    const value = target.type == 'checkbox'? target.checkbox: target.value
    const name = target.name;

this.setState({
    [name]: value,
})
this.setState({username: this.state.email})
  }

  handleBlur = (field) => (e) => {
      this.setState({
          touched : { ...this.state.touched, [field]: true}
      })
  }

  validate (firstName, lastName, email, pass){
  const validEmail = (val) => /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(val);
  const errors = {
    firstName: '',
    lastName: '',
    email: '',
    password: ''
  }

    if (this.state.touched.firstName && firstName.length < 2)
        errors.firstName = 'Tu nombre debe tener más de 3 caracteres'

    else if (this.state.touched.firstName && firstName.length > 15)
        errors.firstName = 'Tu nombre debe tener menos de 15 caracteres'

    if (this.state.touched.lastName && lastName.length < 2)
        errors.lastName = 'Tu nombre debe tener más de 3 caracteres'

    else if (this.state.touched.lastName && lastName.length > 15)
        errors.lastName = 'Tu nombre debe tener menos de 15 caracteres'

    if (this.state.touched.email && !validEmail(email))
        errors.email = 'Email No valido'

    else if (this.state.touched.pass && pass.length < 4)
        errors.pass = 'Tu password debe tener más de 3 caracteres'

    return errors
}

 handleSubmit(e) {
    //some fetch operation
  }

render(){
    //const {firstName, lastName, email, pass} = this.state
    const errors = this.validate(this.state.firstName, this.state.lastName, this.state.email, this.state.pass)
    return(
      <Form onSubmit={this.handleSubmit}>
        <Row className="form-group">
          <Label htmlFor="firstname" md={2}><strong>Tu Nombre</strong></Label>
          <Col md={4}>
                <Input type="text" id="firstName" name="firstName"
                  placeholder="Juanito"
                  value={this.state.firstName}
                  className="form-control"
                  valid={errors.firstName === ''}
                  invalid={errors.firstName !== ''}
                  onBlur={this.handleBlur('firstName')}
                  onChange={this.handleInput} />
                <FormFeedback>{errors.firstName}</FormFeedback>
            </Col>
            <Label htmlFor="lastname" md={2}><strong>Tu Apellido</strong></Label>
            <Col md={4}>
              <Input type="text" id="lastName" name="lastName"
                  placeholder="Pérez"
                  value={this.state.lastName}
                  className="form-control"
                  valid={errors.lastName === ''}
                  invalid={errors.lastName !== ''}
                  onBlur={this.handleBlur('lastName')}
                  onChange={this.handleInput} />
                <FormFeedback>{errors.lastName}</FormFeedback>
          </Col>
          </Row>
          <Row className="form-group">
          <Label htmlFor="email" md={2}><strong>Email(*)</strong></Label>
          <Col md={4}>
            <Input type="email" id="email" name="email"
                placeholder="juanito@duck.com"
                className="form-control"
                valid={errors.email === ''}
                invalid={errors.email !== ''}
                onBlur={this.handleBlur('email')}
                onChange={this.handleInput}/>
            <FormFeedback>{errors.email}</FormFeedback>
          </Col>
          <Label htmlFor="password" md={2}><strong>Contraseña</strong></Label>
            <Col md={4}>
                <Input type="password" id="pass" name="password"
                    className="form-control"
                    valid={errors.pass === ''}
                    invalid={errors.pass !== ''}
                    onBlur={this.handleBlur('password')}
                    onChange={this.handleInput} />
                <FormFeedback>{errors.pass}</FormFeedback>
            </Col>
        </Row>
        <Row className="form-group">
          <Col md={{size:2, offset:10}}>
              <Button type="submit" value="submit" name="submit" color="primary">
                  Inscribirse
              </Button>
          </Col>
        </Row>
      </Form>
    )
 }
}

export default SignUp;

在这里,我尝试实现相同的方法:

import React, { useState } from 'react';
import { Label, Button, Col, Row, FormFeedback, Input, Form } from 'reactstrap';


function SignUp (){
    return(
        <div className="container">
            <div className="row" style={{'padding': '30px 12px 60px 12px'}}>
                <div className="col col-md-8">
                    <h4>Inscríbete y crea tu galería de pesonajes!</h4>
                </div>
            </div>
            <div className="row row-content">
                <div className="col col-md-8">
                    {<SignUpForm />}
                </div>
            </div>
        </div>
    );
}

function SignUpForm() {

    const [formState, setFormState] = useState({firstName: '', lastName: '', email: '', pass: ''})
    const [username, setUsername] = useState('')
    const [touched, setTouched] = useState({firstName: false, lastName: false, email: false, pass: false})

    function handleInput (e) {
        const target = e.target;
        const value = target.type == 'checkbox'? target.checkbox: target.value
        const name = target.name;
        setFormState({ [name]: value })
    }

    function handleBlur(e) { 
        console.log(e.target.name)
        setTouched({...touched, [e.target.name]: true})

    }

    function validate(firstName, lastName, email, pass) {
        const validEmail = (val) => /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(val);
        const errors = {
            firstName: '',
            lastName: '',
            email: '',
            password: ''
        }

        if (touched.firstName && firstName.length <= 2)
            errors.firstName = 'Tu nombre debe tener más de 2 caracteres'

        else if (touched.firstName && firstName.length > 15)
            errors.firstName = 'Tu nombre debe tener menos de 15 caracteres'

        if (touched.lastName && lastName.length < 2)
            errors.lastName = 'Tu apellido debe tener más de 3 caracteres'

        else if (touched.lastName && lastName.length > 15)
            errors.lastName = 'Tu apellido debe tener menos de 15 caracteres'

        if (touched.email && !validEmail(email))
            errors.email = 'Email No valido'

        else if (touched.pass && pass.length < 4)
            errors.pass = 'Tu password debe tener más de 3 caracteres'
        return errors
    }

    function handleSubmit(e) {
        //some fetch operation
    }

    const errors = validate(formState.firstName, formState.lastName, formState.email, formState.pass)
    return(
        <Form onSubmit={ () => handleSubmit}>
            <Row className="form-group">
                <Label htmlFor="firstname" md={2}><strong>Tu Nombre</strong></Label>
                <Col md={4}>
                    <Input type="text" id="firstName" name="firstName"
                        placeholder="Juanito"
                        value={formState.firstName}
                        className="form-control"
                        valid={errors.firstName === ''}
                        invalid={errors.firstName !== ''}
                        onBlur={ (e) => handleBlur(e) }
                        onChange={ (e) => handleInput(e) } />
                    <FormFeedback>{errors.firstName}</FormFeedback>
                </Col>
                <Label htmlFor="lastname" md={2}><strong>Tu Apellido</strong></Label>
                <Col md={4}>
                    <Input type="text" id="lastName" name="lastName"
                        placeholder="Pérez"
                        value={formState.lastName}
                        className="form-control"
                        valid={errors.lastName === ''}
                        invalid={errors.lastName !== ''}
                        onBlur={ (e) => handleBlur(e)}
                        onChange={(e) => handleInput(e)} />
                    <FormFeedback>{errors.lastName}</FormFeedback>
                </Col>
                </Row>
                <Row className="form-group">
                <Label htmlFor="email" md={2}><strong>Email(*)</strong></Label>
                <Col md={4}>
                <Input type="email" id="email" name="email"
                    placeholder="juanito@duck.com"
                    value={formState.email}
                    className="form-control"
                    valid={errors.email === ''}
                    invalid={errors.email !== ''}
                    onBlur={ (e) => handleBlur(e)}
                    onChange={(e) => handleInput(e)} />
                <FormFeedback>{errors.email}</FormFeedback>
                </Col>
                <Label htmlFor="password" md={2}><strong>Contraseña</strong></Label>
                <Col md={4}>
                    <Input type="password" id="pass" name="password"
                        value={formState.pass}
                        className="form-control"
                        valid={errors.pass === ''}
                        invalid={errors.pass !== ''}
                        onBlur={ (e) => handleBlur(e)}
                        onChange={(e) => handleInput(e)} />
                    <FormFeedback>{errors.pass}</FormFeedback>
                </Col>
            </Row>
            <Row className="form-group">
                <Col md={{size:2, offset:10}}>
                    <Button type="submit" value="submit" name="submit" color="primary">
                        Inscribirse
                    </Button>
                </Col>
            </Row>
        </Form>
    )
}

export default SignUp;

当我在第二个字段(姓氏)中请求输入值时,会出现错误消息,说“名字”未定义(cannot read length property of undefined)。我认为问题在于setFirstName不能在验证函数之前设置值,但是在重新排列代码几小时后,我找不到修复它的方法

1 个答案:

答案 0 :(得分:1)

我也在为此而苦苦挣扎,并希望看到它被标记为已回答,因为它对我有帮助。

正如@VasylButov指出的那样,setFormState([name]: value)正在覆盖formState对象并将其设置为value。首先使用传播运算符...formState,然后修改所需的属性setFormState({...formState, [name]: value})

作为SO的新贡献者,我不确定100%表示发布评论中已经回答的答案的礼节是什么,因此,如果这不正确,请原谅我。