Reputation: 147
When the form is submitted I want to validate two fields. Specifically I want to check if the password has at least 5 characters, and that the password and confirmPassword fields match. I went ahead and implemented state to hold these error message. However, not all errors are being displayed. Example: supposed for the password field a user entered 'hell' and for password confirmation they entered 'hello'. You would expect 2 error messages (password too short, passwords don't match) but my form only displays one error - passwords don't match.
I suspect the issue lies in the validateFields function. If I swap the order of the if-statements and enter the same input I described above then I manage to see the 'password must contain at least 5 characters' error but not the 'passwords don't match error'. In addition, when using the react dev-tools I notice in the error state only one message is being set. So I don't think I'm using setState properly, maybe spread operator is not working as I intended?
import React, {useState} from 'react'
import {Grid, TextField, RadioGroup, Radio, FormControl, FormLabel, FormControlLabel, Checkbox, Button} from '@material-ui/core'
const Registration = () => {
const [data, setData] = useState({
username: '',
email: '',
password: '',
confirmPassword: '',
})
const [errors, setErrors] = useState({
short: '',
mismatch: '',
})
const handleChange = e => {
const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value
setData({
...data,
[e.target.name]: value,
})
}
const validateFields = () => {
let error = false
if (data.password && data.password.length < 5) {
error = true
console.log('password was too short')
setErrors({...errors, short: 'Password must contain at least 5 characters'})
console.log('short set')
}
if (data.confirmPassword && data.confirmPassword !== data.password) {
error = true
setErrors({...errors, mismatch: "Passwords don't match"})
}
return error
}
const handleSubmit = e => {
e.preventDefault()
console.log(data)
if (validateFields()) {
return
}
}
return (
<Grid id='registration-form' container xs={12} direction='column'>
<Grid item xs={12} align='center'>
<h1>Register</h1>
</Grid>
<form onSubmit={handleSubmit}>
<Grid container spacing={2} xs={12} alignItems='center' justify='center'>
<Grid container item xs={3} direction='column' spacing={2}>
<Grid item>
<TextField id='username' name='username' label='Username' onChange={handleChange} value={data.username} required />
</Grid>
<Grid item>
<TextField id='email' name='email' label='Email' onChange={handleChange} value={data.email} required type='email' />
</Grid>
<Grid item>
<TextField id='password' name='password' label='Password' onChange={handleChange} value={data.password} error={errors.short !== ''} helperText={errors.short} required type='password' />
</Grid>
<Grid item>
<TextField
id='confirm-password'
name='confirmPassword'
label='Confirm Password'
onChange={handleChange}
value={data.confirmPassword}
error={Boolean(errors?.mismatch)}
helperText={errors?.mismatch}
required
type='password'
/>
</Grid>
</Grid>
</Grid>
</form>
<Grid item align='center'>
<a href='#'>Already have an account? Login</a>
</Grid>
</Grid>
)
}
export default Registration
Upvotes: 4
Views: 2087
Reputation: 98
Change your validation function by the below code. It will work.
const validateFields = () => {
let error = false
if (data.password && data.password.length < 5) {
error = true
console.log('password was too short')
//notice updater function here
setErrors(state=>({...state, short: 'Password must contain at least 5 characters'}))
console.log('short set')
}
if (data.confirmPassword && data.confirmPassword !== data.password) {
error = true
setErrors(state=>({...state, mismatch: "Passwords don't match"}))
}
return error
}
When your state update depends on previous state values, pass a function instead of an object to set the state to ensure the call always uses the most updated version of the state. Passing an update function allows you to access the current state value inside the updater.
Upvotes: 1