You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Formik、Yup、MUI的注册表单无法提交问题排查

问题原因及修复方案

点击注册按钮无响应的核心原因是用户类型(userType)的下拉框未正确与Formik绑定,导致Yup验证始终不通过,Formik的提交逻辑根本没触发。

具体问题点

userType字段在验证规则里是必填项,但对应的下拉TextField缺失了以下关键属性:

  • 未设置name="userType",Formik无法识别该字段
  • 未绑定handleChange和handleBlur,字段值无法同步到Formik的values中
  • 未关联values.userType作为当前值
  • 未处理验证错误的展示逻辑

修复步骤

修改用户类型选择的TextField,补充Formik相关绑定:

  1. 添加name="userType"
  2. 绑定onChange={handleChange}、onBlur={handleBlur}
  3. 设置value={values.userType}
  4. 增加错误提示相关的error和helperText属性

修复后的完整代码

import {
    Box,
    Button,
    MenuItem,
    TextField,
    Typography,
    useMediaQuery,
    useTheme,
} from '@mui/material'
import { Formik } from 'formik'
import { useNavigate } from 'react-router-dom'
import * as yup from 'yup'

const registerSchema = yup.object().shape({
    firstName: yup.string().required('required'),
    lastName: yup.string().required('required'),
    userType: yup.string().required('required'),
    userName: yup.string().required('required'),
    email: yup.string().email('invalid email').required('required'),
    password: yup.string().required('required'),
    confirmPassword: yup.string().required('required'),
})

const initialValuesRegister = {
    firstName: '',
    lastName: '',
    userType: '',
    userName: '',
    email: '',
    password: '',
    confirmPassword: '',
}

const type = [
    {
        value: 'Student',
        label: 'Student',
    },
    {
        value: 'Teacher',
        label: 'Teacher',
    },
]

const FormRegister = () => {
    const { palette } = useTheme()
    const navigate = useNavigate()
    const isNonMobile = useMediaQuery('(min-width:600px)')

    const register = async (values, onSubmitProps) => {
        const savedUserResponse = await fetch(
            'http://localhost:3001/auth/register',
            {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(values),
            }
        )

        const savedUser = await savedUserResponse.json()
        onSubmitProps.resetForm()

        if (savedUser) {
            console.log(savedUser)
            navigate('/')
        }
    }

    const handleFormSubmit = async (values, onSubmitProps) => {
        console.log('Test')
        console.log(values, onSubmitProps)
        await register(values, onSubmitProps)
    }

    return (
        <Formik
            onSubmit={handleFormSubmit}
            initialValues={initialValuesRegister}
            validationSchema={registerSchema}
        >
            {({
                values,
                errors,
                touched,
                handleBlur,
                handleChange,
                handleSubmit,
                resetForm,
            }) => (
                <form onSubmit={handleSubmit}>
                    <Box
                        display="grid"
                        gap="30px"
                        gridTemplateColumns="repeat(4, minmax(0, 1fr))"
                        sx={{
                            '& > div': { gridColumn: isNonMobile ? undefined : 'span 4' },
                        }}
                    >
                        <TextField
                            label="First Name"
                            onBlur={handleBlur}
                            onChange={handleChange}
                            value={values.firstName}
                            name="firstName"
                            error={Boolean(touched.firstName) && Boolean(errors.firstName)}
                            helperText={touched.firstName && errors.firstName}
                            sx={{ gridColumn: 'span 2' }}
                        />
                        <TextField
                            label="Last Name"
                            onBlur={handleBlur}
                            onChange={handleChange}
                            value={values.lastName}
                            name="lastName"
                            error={Boolean(touched.lastName) && Boolean(errors.lastName)}
                            helperText={touched.lastName && errors.lastName}
                            sx={{ gridColumn: 'span 2' }}
                        />
                        <TextField
                            id="outlined-select"
                            select
                            label="Select Type"
                            name="userType"
                            value={values.userType}
                            onChange={handleChange}
                            onBlur={handleBlur}
                            error={Boolean(touched.userType) && Boolean(errors.userType)}
                            helperText={touched.userType && errors.userType}
                        >
                            {type.map((option) => (
                                <MenuItem key={option.value} value={option.value}>
                                    {option.label}
                                </MenuItem>
                            ))}
                        </TextField>
                        <TextField
                            label="User Name"
                            onBlur={handleBlur}
                            onChange={handleChange}
                            value={values.userName}
                            name="userName"
                            error={Boolean(touched.userName) && Boolean(errors.userName)}
                            helperText={touched.userName && errors.userName}
                            sx={{ gridColumn: 'span 4' }}
                        />
                        <TextField
                            label="Email"
                            onBlur={handleBlur}
                            onChange={handleChange}
                            value={values.email}
                            name="email"
                            error={Boolean(touched.email) && Boolean(errors.email)}
                            helperText={touched.email && errors.email}
                            sx={{ gridColumn: 'span 4' }}
                        />
                        <TextField
                            label="Password"
                            type="password"
                            onBlur={handleBlur}
                            onChange={handleChange}
                            value={values.password}
                            name="password"
                            error={Boolean(touched.password) && Boolean(errors.password)}
                            helperText={touched.password && errors.password}
                            sx={{ gridColumn: 'span 4' }}
                        />
                        <TextField
                            label="Confirm Password"
                            type="password"
                            onBlur={handleBlur}
                            onChange={handleChange}
                            value={values.confirmPassword}
                            name="confirmPassword"
                            error={
                                Boolean(touched.confirmPassword) &&
                                Boolean(errors.confirmPassword)
                            }
                            helperText={touched.confirmPassword && errors.confirmPassword}
                            sx={{ gridColumn: 'span 4' }}
                        />
                    </Box>
                    {/* BUTTONS */}
                    <Box>
                        <Button
                            fullWidth
                            type="submit"
                            sx={{
                                m: '2rem 0',
                                p: '1rem',
                                backgroundColor: palette.primary.main,
                                color: palette.background.alt,
                                '&:hover': { color: palette.primary.main },
                            }}
                        >
                            REGISTER
                        </Button>
                        <Typography
                            onClick={() => {
                                navigate('/')
                                resetForm()
                            }}
                            sx={{
                                textDecoration: 'underline',
                                color: palette.primary.main,
                                '&:hover': {
                                    cursor: 'pointer',
                                    color: palette.primary.light,
                                },
                            }}
                        >
                            Already have an account? Login here
                        </Typography>
                    </Box>
                </form>
            )}
        </Formik>
    )
}

export default FormRegister

额外优化建议

可以给userType设置默认值,避免用户未选择时直接触发必填错误:

// 方式1:修改初始值
const initialValuesRegister = {
    // ...其他字段
    userType: 'Student',
}

// 方式2:在Yup规则里设置默认值
userType: yup.string().default('Student').required('required'),

内容的提问来源于stack exchange,提问作者Strike

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 20:25:53