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

Formik+React+TypeScript嵌套对象场景下MUI TextField报未定义错误

Formik+React+TypeScript嵌套表单中MUI TextField的error/helperText报错问题

开发嵌套对象表单时,已正确初始化表单值,但MUI TextField的error和helperText属性始终抛出**"无法读取未定义属性(读取‘emailSubject’)"**的错误。禁用这两个属性后错误消失,可确定问题源于此。尝试过调整validationSchema的嵌套字段验证方案,但问题仍未解决。

组件核心代码

const initialValues: ActionFormValues = {
    actionType: "send_email",
    recipient: "",
    email: {
        recipients: [],
        emailSubject: "",
        emailContent: ""
    }
};

const EmailForm = () => {
    const { t } = useTranslation();

    const [action, setAction] = useState<Action>(initialValues);
    const [isSubmissionValid, setIsSubmissionValid] = useState(false);

    const validationSchema = yup.object({
        recipient: yup
            .string()
            .email(t("FormValidation.Valid_Email"))
            .test("unique-recipient", t("FormValidation.Email_Exists"), function (value) {
                const { recipients } = this.parent.email; // Access recipients from the parent object
                return !recipients.includes(value);
            }),

        email: yup.object({
            emailSubject: yup.string().required("An email subject is required")
        })
    });

    const handleSubmit = (values: ActionFormValues) => {
        const submission = handleSubmissionCreation(values);
        console.log(submission);
    };

    const formik = useFormik<ActionFormValues>({
        initialValues: action,
        enableReinitialize: true,
        validationSchema,
        onSubmit: handleSubmit
    });

    useEffect(() => {
        let currentValues = formik.values;
        if (currentValues.actionType === "send_email") {
            if (currentValues.email.emailContent !== "" && currentValues.email.emailSubject !== "") {
                setIsSubmissionValid(true);
            }
        }
    }, [formik.values]);

    const handleSubmissionCreation = (submittedValues: ActionFormValues): Action => {
        if (submittedValues.actionType === "send_email") {
            return {
                actionType: submittedValues.actionType,
                email: {
                    recipients: action.email.recipients,
                    emailSubject: submittedValues.email.emailSubject,
                    emailContent: submittedValues.email.emailContent
                }
            };
        }
    };

    // Handler for adding email
    const handleAddEmail = (newEmail: string) => {
        if (newEmail) {
            // Update the email.recipients array in the state
            setAction((prevState) => ({
                ...prevState,
                email: {
                    ...prevState.email,
                    recipients: [...prevState.email.recipients, newEmail]
                }
            }));

            // Clear the recipient field and reset its state
            formik.setFieldValue("recipient", ""); // Clear the value
            formik.setFieldTouched("recipient", false); // Mark it as not touched
            formik.setFieldError("recipient", ""); // Clear any errors
        }
    };

    // Handler for deleting an recipient
    const handleDelete = (emailToDelete: string) => () => {
        setAction((prevState) => ({
            ...prevState,
            email: {
                ...prevState.email,
                recipients: prevState.email.recipients.filter((recipient) => recipient !== emailToDelete)
            }
        }));
    };

    return (
        <Box component="form" onSubmit={formik.handleSubmit}>
            <TextField
                fullWidth
                id="recipient"
                name="recipient"
                label={t("Common.Recipients")}
                value={formik.values.recipient}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                error={formik.touched.recipient && Boolean(formik.errors.recipient)}
                helperText={formik.touched.recipient && formik.errors.recipient}
                onKeyDown={(ev) => {
                    if (ev.key === "Enter") {
                        if (!formik.isValid) {
                            ev.preventDefault();
                            return;
                        }
                        handleAddEmail(formik.values.recipient);
                        ev.preventDefault();
                    }
                }}
                inputProps={{ "data-testid": "recipient-field" }}
                InputProps={{
                    endAdornment: (
                        <InputAdornment position="end">
                            <IconButton
                                aria-label="add recipient"
                                onClick={() => handleAddEmail(formik.values.recipient)}
                                onMouseDown={(e) => e.preventDefault()}
                                disabled={!formik.isValid}
                            >
                                <AddCircle />
                            </IconButton>
                        </InputAdornment>
                    )
                }}
            />

            <Box className="recipient-container">
                {action &&
                    action.email.recipients.map((data, index) => (
                        <Chip key={index} label={data} onDelete={handleDelete(data)} />
                    ))}
            </Box>
            <TextField
                fullWidth
                id="emailSubject"
                name="email.emailSubject"
                label={t("Common.Email_Subject")}
                value={formik.values.email.emailSubject}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                error={formik.touched.email.emailSubject && Boolean(formik.errors.email.emailSubject)}
                helperText={formik.touched.email.emailSubject && formik.errors.email.emailSubject}
            />

            <TextField
                fullWidth
                id="emailContent"
                name="email.emailContent"
                label={t("Common.Email_Message")}
                value={formik.values.email.emailContent}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                multiline
                minRows={5}
            />

            <Button variant="contained" type="submit" fullWidth disabled={!isSubmissionValid}>
                Send Email
            </Button>
        </Box>
    );
};

export default EmailForm;

尝试过的validationSchema调整方案

recipient: yup
    .string()
    .email(t("FormValidation.Valid_Email"))
    .test("unique-recipient", t("FormValidation.Email_Exists"), function (value) {
        const { recipients } = this.parent.email; // Access recipients from the parent object
        return !recipients.includes(value);
    }),

email: yup.object().shape({
    emailSubject: yup
        .string()
        .required("An email subject is required")
        .transform((value, originalValue) => (originalValue.trim() === "" ? null : value))
        .nullable()
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 18:44:52