我目前正在处理客户端表单验证。没有后端,也没有类似的东西。我有一个on Submit函数,一旦使用props.history.push提交了有效的表单,我就试图将用户推送到主页。由于某种原因,我必须提交两次表单才能使用on Submit函数,以将用户实际推入主页。我不确定为什么会这样。在下面,我将提供我的useForm钩子,“登录”页面以及正在使用的验证功能。我觉得答案可能很明显,但我只是找不到问题。
useForm挂钩:
import { useState } from "react"
const INITIAL_STATE = {
email: "",
password: ""
}
const UseForm = (ValidateLogin, props) => {
const [formData, setFormData] = useState(INITIAL_STATE)
const [errors, setErrors] = useState({})
const [user, setUser] = useState(null)
const handleChange = field => e => {
setFormData({ ...formData, [field]: e.target.value })
}
const handleSubmit = event => {
event.preventDefault()
setUser(formData)
setErrors(ValidateLogin(formData))
user && !errors.email && !errors.password && props.history.push("/")
}
return {
handleChange,
handleSubmit,
formData,
user,
errors
}
}
export default UseForm
登录页面:
import React from "react"
import UseForm from "../Login/UseForm"
import ValidateLogin from "../Login/ValidateLogin"
import { makeStyles } from "@material-ui/core/styles"
// Material UI
import TextField from "@material-ui/core/TextField"
import Button from "@material-ui/core/Button"
import Typography from "@material-ui/core/Typography"
import Container from "@material-ui/core/Container"
const useStyles = makeStyles(theme => ({
form: {
textAlign: "center",
width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(1),
position: "relative"
},
logo: {
width: 80,
margin: "20px auto 20px auto"
},
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center"
},
submit: {
margin: theme.spacing(3, 0, 2),
position: "relative"
},
progress: {
position: "absolute"
},
customError: {
color: "red",
fontSize: "0.8rem",
width: "100%",
position: "absolute"
}
}))
const Login = props => {
const classes = useStyles()
const { handleChange, handleSubmit, formData, user, errors } = UseForm(
ValidateLogin,
props
)
const isInvalid = !formData.email || !formData.password
return (
<div style={{ textAlign: "center" }}>
<Typography variant='h5' gutterBottom>
Welcome, Please Login
</Typography>
<Container component='main' maxWidth='xs'>
<form className={classes.form} onSubmit={handleSubmit}>
<TextField
variant='outlined'
fullWidth
margin='normal'
label='Email'
type='text'
name='email'
value={formData.email}
error={errors.email ? true : false}
helperText={errors.email}
onChange={handleChange("email")}
/>
<TextField
variant='outlined'
margin='normal'
fullWidth
label='Password'
type='password'
name='password'
value={formData.password}
error={errors.password ? true : false}
helperText={errors.password}
onChange={handleChange("password")}
/>
<br />
<Button
variant='outlined'
color='primary'
type='submit'
disabled={isInvalid}
className={classes.submit}
>
Submit
</Button>
</form>
</Container>
<br />
{user &&
!errors.email &&
!errors.password &&
JSON.stringify(user, null, 2)}
</div>
)
}
export default Login
验证登录名:
export default function ValidateLogin(formData) {
let errors = {}
if (!formData.email) {
errors.email = "Email address is required"
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
errors.email = "Email address is invalid"
}
if (!formData.password) {
errors.password = "Password is required"
} else if (formData.password.length < 6) {
errors.password = "Password must be longer than 6 characters"
}
return errors
}
任何有用的建议或反馈将不胜感激!!对于这个冗长的问题,我深表歉意。感谢您抽出宝贵的时间阅读这篇文章。
答案 0 :(得分:1)
您的问题似乎是此块中的条件:
setUser(formData)
setErrors(ValidateLogin(formData))
user && !errors.email && !errors.password && props.history.push("/")
user
和errors
在评估此条件时将不会更新,因为状态设置器是异步的。 Here is a more detailed explanation。
这就是为什么它可以在第二个提交上使用的原因。然后更新值,条件通过。
这可能不是理想的最终解决方案,但应该可以为您解决问题。
const handleSubmit = event => {
event.preventDefault()
setUser(formData)
// Use temp variable so that you can use it immediately below
const tempErrors = ValidateLogin(formData);
setErrors(tempErrors)
// Use the formData directly and the tempErrors
formData && !tempErrors.email && !tempErrors.password && props.history.push("/")
}