I have a previous form validation of a controlled form, and I'm trying to convert the class component to a function component using hooks. But I have problems implementing the original onBlur and onChange methods. My original code:
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="[email protected]"
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;
And Here I tried to implement the same:
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="[email protected]"
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;
When I beggin input values in the second field (lastname) there's and error saying 'firstname' is undefined (cannot read length property of undefined
). I think the problem is with the fact that setFirstName
doesn't get to set the value before the validation function, but after hourse rearranging the code I can't find a way to fix it
setFormState({ ...formState, [name]: value })
? – Vasyl Butov