表单中的 React Hooks 自定义验证无法更新多个状态

React Hooks custom validation in form cannot update multiple states

如果在 handleValidate() 触发期间所有字段都留空,则只有 error 中的 confirmPasswordIsErrorconfirmPassword 的状态会被更新,其他的会被更新。我不知道哪里出了问题?

function Register() {
    const classes = useStyles();
    const { handleRegister } = useContext(AuthenticationContext);
    const [form, setForm] = useState({
        username: '',
        password: '',
        confirmPassword: ''
    })

    const [error, setError] = useState({
        usernameIsError: false,
        usernameError: '',
        passwordIsError: false,
        passwordError: '',
        confirmPasswordIsError: false,
        confirmPasswordError: ''
    });

    const handleValidate = () => {
        if (!form.username) {
            setError({
                ...error,
                usernameIsError: true,
                usernameError: '用戶名稱不能留空'
            })
        }
        if (!form.password) {
            setError({
                ...error,
                passwordIsError: true,
                passwordError: '密碼不能留空'
            })
        }
        if (!form.confirmPassword) {
            setError({
                ...error,
                confirmPasswordIsError: true,
                confirmPasswordError: '確認密碼不能留空'
            })
            return false;
        }
        // if (form.confirmPassword !== form.password) {
        //     setError({
        //         ...error,
        //         confirmPasswordIsError: true,
        //         confirmPasswordError: '確認密碼與密碼不相同'
        //     })
        //     return false;
        // }
        return true;
    }

    const handleChange = (e) => {
        const { name, value } = e.target
        setForm({
            ...form,
            [name]: value
        })
    }

    const handleSubmit = (e) => {
        e.preventDefault();
        const isFormValid = handleValidate();
        console.log(isFormValid)
        if (isFormValid) {
            handleRegister(form.username, form.password)
        }
    }

    return (
        <Container>
            <Grid
                container
                justify="center"
            >
                <Grid item>
                    <Paper className={classes.paper} elevation={3} >
                        <form noValidate autoComplete="off" onSubmit={handleSubmit}>
                            <TextField
                                error={error.usernameIsError}
                                helperText={error.usernameError}
                                className={classes.input}
                                fullWidth
                                required
                                name="username"
                                size="small"
                                label="帳號"
                                variant="outlined"
                                value={form.username}
                                onChange={handleChange}
                            />
                            <TextField
                                error={error.passwordIsError}
                                helperText={error.passwordError}
                                className={classes.input}
                                fullWidth
                                required
                                name="password"
                                size="small"
                                label="密碼"
                                type="password"
                                variant="outlined"
                                value={form.password}
                                onChange={handleChange}
                            />
                            <TextField
                                error={error.confirmPasswordIsError}
                                helperText={error.confirmPasswordError}
                                className={classes.input}
                                fullWidth
                                required
                                name="confirmPassword"
                                size="small"
                                label="確認密碼"
                                type="password"
                                variant="outlined"
                                value={form.confirmPassword}
                                onChange={handleChange}
                            />
                            <Button className={classes.button} fullWidth variant="contained" color="primary" type="submit">註冊</Button>
                        </form>
                    </Paper>
                </Grid>
            </Grid>
        </Container>
    )
}

如果在渲染周期内对多个更新进行排队,则使用功能状态更新,以便后续更新不会覆盖先前排队的更新。

当您使用正常更新时,您将处于 error 状态,在当前渲染周期的回调范围内关闭,因此每次更新都会消除之前的更新。功能状态更新允许您从以前的状态更新。

const handleValidate = () => {
    if (!form.username) {
        setError(error => ({
            ...error,
            usernameIsError: true,
            usernameError: '用戶名稱不能留空'
        }))
    }
    if (!form.password) {
        setError(error => ({
            ...error,
            passwordIsError: true,
            passwordError: '密碼不能留空'
        }))
    }
    if (!form.confirmPassword) {
        setError(error => ({
            ...error,
            confirmPasswordIsError: true,
            confirmPasswordError: '確認密碼不能留空'
        }))
        return false;
    }
    if (form.confirmPassword !== form.password) {
        setError(error => ({
            ...error,
            confirmPasswordIsError: true,
            confirmPasswordError: '確認密碼與密碼不相同'
        }))
        return false;
    }
    return true;
}