reactjs - 无法使用 setValues 在布尔属性上设置状态
问题描述
我正在做这个非常直接的 ReactJS 登录屏幕,并且在 setValue 状态中有一个错误(至少我是这么认为的)。基本上,我为这些值设置了默认值(如下所示)
const [values, setValues] = React.useState<State>({
email: '',
password: '',
showPassword: false,
stayLogged: false,
openSnackBar: false,
incorrectEmail: false,
incorrectPassword: false,
emailErrorMessage: '',
passwordErrorMessage: ''
});
我可以更改其他字段(包括 openSnackBar),但不能更改不正确的电子邮件和不正确的密码字段。如您所见,在下面的代码段中,我验证文本是否与有效电子邮件地址的正则表达式匹配,如果不匹配,则应使用新的错误消息更新值,并为不正确的电子邮件更新值,但事实并非如此。不正确的密码也是如此。
const verifyEmail = (email: React.ChangeEvent<HTMLInputElement>) => {
let emailVerificationRegex = '^\\w+([-+.\']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$';
if ((!new RegExp(emailVerificationRegex).test(email.target.value)) && email.target.value !== '') {
setValues({...values, incorrectEmail: true})
setValues({...values, emailErrorMessage: 'The email you entered is invalid'})
log('If email invalido: \nValor incorrectEmail = ' + values.incorrectEmail + '\nvalor emailErrorMessage ' + values.emailErrorMessage)
} else {
setValues({...values, incorrectEmail: false})
setValues({...values, emailErrorMessage: ''})
setValues({...values, email: email.target.value})
console.log('If email valido: \nValor incorrectEmail = ' + values.incorrectEmail + '\nvalor emailErrorMessage ' + values.emailErrorMessage + '\nemail' + values.email)
}
}
是什么导致了这种行为?我该如何解决?下面的完整片段
import React from 'react';
import {createStyles, makeStyles, Theme} from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import {
Button,
FormControlLabel,
Grid,
IconButton,
InputAdornment,
Link,
Snackbar,
Switch,
TextField
} from "@material-ui/core";
import {Close, Facebook, Visibility, VisibilityOff} from "@material-ui/icons";
import {log} from "util";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
maxWidth: 345,
},
buttonSpacing: {
padding: theme.spacing(2)
},
marginSpacing: {
margin: theme.spacing(1)
},
loginCardSpacing: {
margin: theme.spacing(5)
},
forgotYourPassword: {
paddingRight: 10
},
}),
);
interface State {
email: string;
password: string;
showPassword: boolean;
stayLogged: boolean;
openSnackBar: boolean;
incorrectEmail: boolean;
incorrectPassword: boolean;
emailErrorMessage: string;
passwordErrorMessage: string;
}
export default function LoginCard() {
const classes = useStyles();
const [values, setValues] = React.useState<State>({
email: '',
password: '',
showPassword: false,
stayLogged: false,
openSnackBar: false,
incorrectEmail: false,
incorrectPassword: false,
emailErrorMessage: '',
passwordErrorMessage: ''
});
const showHidePassword = () => {
setValues({...values, showPassword: !values.showPassword})
}
const stayConnected = () => {
setValues({...values, stayLogged: !values.stayLogged})
}
const handleCloseSnackBar = () => {
setValues({...values, openSnackBar: !values.openSnackBar})
}
const verifyEmail = (email: React.ChangeEvent<HTMLInputElement>) => {
let emailVerificationRegex = '^\\w+([-+.\']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$';
if ((!new RegExp(emailVerificationRegex).test(email.target.value)) && email.target.value !== '') {
setValues({...values, incorrectEmail: true})
setValues({...values, emailErrorMessage: 'The email you entered is invalid'})
log('If email invalido: \nValor incorrectEmail = ' + values.incorrectEmail + '\nvalor emailErrorMessage ' + values.emailErrorMessage)
} else {
setValues({...values, incorrectEmail: false})
setValues({...values, emailErrorMessage: ''})
setValues({...values, email: email.target.value})
console.log('If email valido: \nValor incorrectEmail = ' + values.incorrectEmail + '\nvalor emailErrorMessage ' + values.emailErrorMessage + '\nemail' + values.email)
}
}
const verifyPassword = (password: React.ChangeEvent<HTMLInputElement>) => {
if ((password.target.value.length < 5 || password.target.value.length > 24 || !password) && !(password.target.value === '')) {
setValues({...values, incorrectPassword: true})
setValues({...values, passwordErrorMessage: 'The password you entered is invalid'})
console.log('If senha invalida: ' + values.incorrectPassword + ' ' + values.passwordErrorMessage)
} else {
setValues({...values, incorrectPassword: false})
setValues({...values, passwordErrorMessage: ''})
setValues({...values, password: password.target.value})
console.log('else senha válida: ' + values.incorrectPassword + ' ' + values.passwordErrorMessage)
}
}
function loginToApp(): any {
if (!values.incorrectPassword || !values.incorrectEmail) {
setValues({...values, openSnackBar: !values.openSnackBar})
}
}
return (
<div id="container" className={classes.loginCardSpacing}>
<Grid
container
direction="row"
justify="center"
alignItems="center">
<Grid>
<Card className={classes.root}>
<CardContent>
<form noValidate autoComplete="off">
<TextField id="loginField"
label="Email"
variant="filled"
fullWidth
margin="normal"
error={values.incorrectEmail}
onChange={verifyEmail}
helperText={values.emailErrorMessage}/>
<TextField id="passwordField" label="Password"
type={values.showPassword ? 'text' : 'password'}
onChange={verifyPassword}
variant="filled"
fullWidth
margin="normal"
error={values.incorrectPassword}
helperText={values.passwordErrorMessage}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={showHidePassword}
>
{values.showPassword ? <Visibility/> : <VisibilityOff/>}
</IconButton>
</InputAdornment>
),
}}/>
<div id="buttonGroup">
<Grid
className={classes.marginSpacing}
container
direction="row"
justify="space-around"
alignItems="flex-start"
>
<FormControlLabel
control={<Switch size="small" checked={values.stayLogged}
onChange={stayConnected} name="stayLoggedSwitch"/>}
label="Stay Logged"
/>
<Link className={classes.forgotYourPassword}>
Forgot your password?
</Link>
</Grid>
<Grid container
direction="column"
justify="center"
alignItems="center"
className={classes.buttonSpacing}>
<Grid>
<Button variant="contained" onClick={loginToApp}>
Login
</Button>
</Grid>
<Grid className={classes.marginSpacing}>
<Button
variant="contained"
color="primary"
startIcon={<Facebook/>}
>
Login with Facebook
</Button>
</Grid>
</Grid>
</div>
</form>
</CardContent>
</Card>
</Grid>
</Grid>
<Snackbar
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
open={values.openSnackBar}
autoHideDuration={6000}
onClose={handleCloseSnackBar}
message={values.passwordErrorMessage}
action={
<React.Fragment>
<IconButton size="small" aria-label="close" color="inherit" onClick={handleCloseSnackBar}>
<Close fontSize="small"/>
</IconButton>
</React.Fragment>
}
/>
</div>
);
}
解决方案
您一个接一个地调用多个 setState 。结果,状态变得一团糟。一种可能的解决方案是使用异步等待功能。但我认为对于您的问题,只需一次调用更新状态就足够了。像这样的东西。
setValues({
...values ,
incorrectEmail: true ,
emailErrorMessage: 'The email you entered is invalid'
})
推荐阅读
- python - 似乎我的命令在 Discord.py 中不起作用
- php - 在 phpMyAdmin 上添加约束
- javascript - getUserMedia.bind(navigator) 不返回承诺
- javascript - 导航栏不粘在顶部(反应)
- node.js - 'new AWS.S3' 实例应该是一个全局变量还是应该在每条路由中放置一个单独的 AWS.S3 实例?
- java - JPA 标准:按子字段排序给出错误
- python - 如果深度达到0,递归查找嵌套列表的数量和元素值
- javascript - 从子函数返回并在进一步的父函数中退出执行,没有重复代码
- reactjs - 使用 Typescript 使用 react-hook-form 值作为道具
- hql - 将描述表保存在配置单元的另一个表中