我有登录按钮,如果每个输入字段都第一次正确填充(如果它是有效的),那么它可以正常工作,但是如果没有,我必须单击3次以登录(第一次我收到消息错误该输入无效,第二次单击清除该错误,第三次登录我。
import React, { useRef, useContext, useState } from 'react'
import { AppContext } from '../context/AppContext'
import { useHistory } from 'react-router-dom'
function Login() {
const { setUser } = useContext(AppContext)
const history = useHistory()
const usernameRef = useRef<HTMLInputElement>(null)
const emailRef = useRef<HTMLInputElement>(null)
const passwordRef = useRef<HTMLInputElement>(null)
const [valid, setValid] = useState({ usernameErr: '', emailErr: '', passwordErr: '' })
const handleValidation = () => {
let usernameMsg = ''
let passwordMsg = ''
let emailMsg = ''
if (usernameRef.current?.value === "")
usernameMsg = "Username is not valid"
if (!emailRef.current?.value.includes('@') && !emailRef.current?.value.includes('.'))
emailMsg = "Email is not valid"
if (passwordRef.current?.value !== undefined && passwordRef.current.value.length < 5)
passwordMsg = "Password must contain at least 5 characters"
setValid({
usernameErr: usernameMsg,
emailErr: emailMsg,
passwordErr: passwordMsg
})
}
const handleLogin = () => {
handleValidation()
console.log("validation: ", valid)
if (usernameRef.current?.value && emailRef.current?.value && passwordRef.current?.value) {
if (valid.usernameErr === '' && valid.emailErr === '' && valid.passwordErr === '') {
setUser(
{
username: usernameRef.current.value,
password: passwordRef.current.value,
email: emailRef.current.value,
isLogin: true
})
history.goBack()
}
}
}
return (
<div className="login-outter page">
<div className="login-inner">
<p className="login-title">Log in here</p>
<input type="text" placeholder="Username" ref={usernameRef} className="about-input"/>
<p className="valid">
{valid.usernameErr}
</p>
<input type="text" placeholder="Email" ref={emailRef} className="about-input"/>
<p className="valid">
{valid.emailErr}
</p>
<input type="password" placeholder="Password" ref={passwordRef} className="about-input"/>
<p className="valid">
{valid.passwordErr}
</p>
<button className="login-btn" onClick={handleLogin}>Login</button>
</div>
</div>
)
}
export default Login
这是代码沙箱: https://codesandbox.io/s/flamboyant-torvalds-tevby?file=/src/components/pages/Login.tsx
我认为这是由于useState
引起的,但是不知道到底是什么,为什么以及如何解决。
答案 0 :(得分:1)
这是因为正如我在评论中提到的,React状态挂钩更新是异步的。这是一个示例,说明如何通过稍微修改当前代码来解决此问题: (不是最优雅的解决方案,而是对代码的最小更改,它可以工作)
const handleValidation = () => {
let usernameMsg = ''
let passwordMsg = ''
let emailMsg = ''
if (usernameRef.current?.value === "")
usernameMsg = "Username is not valid"
if (!emailRef.current?.value.includes('@') && !emailRef.current?.value.includes('.'))
emailMsg = "Email is not valid"
if (passwordRef.current?.value !== undefined && passwordRef.current.value.length < 5)
passwordMsg = "Password must contain at least 5 characters"
setValid({
usernameErr: usernameMsg,
emailErr: emailMsg,
passwordErr: passwordMsg
})
return (usernameMsg === '' && passwordMsg === '' && emailMsg === '')
}
const handleLogin = () => {
if (handleValidation() && usernameRef.current?.value && emailRef.current?.value && passwordRef.current?.value) {
setUser(
{
username: usernameRef.current.value,
password: passwordRef.current.value,
email: emailRef.current.value,
isLogin: true
})
history.goBack()
}
}
这是您的链接:https://codesandbox.io/s/strange-lamport-olcy0?file=/src/components/pages/Login.tsx
答案 1 :(得分:1)
handleLogin()
从执行功能(单击按钮)的渲染周期中获取valid
状态值。
这意味着当您在handleValidation()
中调用handleLogin()
时,不会立即影响同一上下文中的valid
状态,而是会影响 next 渲染周期,在该渲染周期中将创建新的handleLogin
函数(在单击按钮之前不会执行)。
解决方案是让像handleValidation()
这样的验证器函数直接返回验证结果,然后您可以在handleLogin()
内设置错误消息状态