首页 > 解决方案 > 无法使用 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>
    );
}

标签: reactjstypescript

解决方案


您一个接一个地调用多个 setState 。结果,状态变得一团糟。一种可能的解决方案是使用异步等待功能。但我认为对于您的问题,只需一次调用更新状态就足够了。像这样的东西。

setValues({ 
    ...values , 
    incorrectEmail: true , 
    emailErrorMessage: 'The email you entered is invalid'
})

推荐阅读