React中使用Formik与Yup实现条件表单验证时无法修改showfile值的问题
showfile Value Update & Conditional Validation in Formik + Yup Got it, let's break down why your showfile value isn't updating and get that conditional validation working properly.
First: The Root Cause of showfile Not Changing
Looking at your onChange handler for the file input:
onChange={(event) => formik.setFieldValue( "file", event.currentTarget.files[0], "showfile", true ) }
The setFieldValue method only accepts three arguments max: (fieldName: string, value: any, shouldValidate?: boolean). You're trying to pass two field-value pairs in one call, which doesn't work—Formik ignores the extra arguments, so showfile never gets set to true.
Step 1: Correctly Update Both file and showfile
You need to update the two fields separately. You can either call setFieldValue twice, or use setValues to update multiple fields at once:
Option 1: Call setFieldValue Twice
onChange={(event) => { const selectedFile = event.currentTarget.files[0]; formik.setFieldValue("file", selectedFile); formik.setFieldValue("showfile", true); // Now this will actually update the value }}
Option 2: Use setValues for Bulk Update
onChange={(event) => { const selectedFile = event.currentTarget.files[0]; formik.setValues({ ...formik.values, file: selectedFile, showfile: true }); }}
Also, fix the value prop on your TextField—you have formik.value which is a typo, it should be formik.values.file:
<TextField label="Resume" star="*" color="red" name="file" type="file" accept=".pdf,.docx,.doc" onChange={/* corrected handler above */} value={formik.values.file} />
Step 2: Fix Yup Validation Rule Issues
Your Yup test has a syntax error—you're missing an && between the size check and format check. Also, you can simplify the when block since you don't need to re-declare Yup.mixed() in the then clause:
const SUPPORTED_FORMATS = ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"]; const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB example file: Yup.mixed().when("showfile", { is: true, then: (schema) => schema .required("Resume is required") .test( "FILE_SIZE", "Uploaded file is too big (max 5MB)", (value) => value && value.size <= MAX_FILE_SIZE ) .test( "FILE_FORMAT", "Only PDF, DOC, DOCX files are allowed", (value) => value && SUPPORTED_FORMATS.includes(value.type) ), })
Split the size and format checks into separate test methods for clarity (and so error messages are specific to each issue).
Step 3: Verify Initial Values
Your initial showfile value is set to false in Formik's initialValues, which is correct—this ensures validation only kicks in once a file is selected (and showfile becomes true).
Full Corrected Snippet Recap
Here's how the key parts should look together:
// Yup Validation const SUPPORTED_FORMATS = ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"]; const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB example const validate = Yup.object().shape({ UserName: Yup.string().required("Username is required"), email: Yup.string().email("Invalid email").required("Email is required"), Phone: Yup.string().required("Phone number is required"), message: Yup.string().required("Message is required"), file: Yup.mixed().when("showfile", { is: true, then: (schema) => schema .required("Resume is required") .test( "FILE_SIZE", "Uploaded file is too big (max 5MB)", (value) => value && value.size <= MAX_FILE_SIZE ) .test( "FILE_FORMAT", "Only PDF, DOC, DOCX files are allowed", (value) => value && SUPPORTED_FORMATS.includes(value.type) ), }), }); // Formik Component <Formik initialValues={{ UserName: "", email: "", Phone: "", message: "", file: "", showfile: false, submit: false, }} validationSchema={validate} onSubmit={(values, actions) => { setTimeout(() => { console.log(values); actions.setSubmitting(false); }, 1000); }} > {({ formik }) => ( <TextField label="Resume" star="*" color="red" name="file" type="file" accept=".pdf,.docx,.doc" onChange={(event) => { const selectedFile = event.currentTarget.files[0]; formik.setFieldValue("file", selectedFile); formik.setFieldValue("showfile", true); }} value={formik.values.file} /> )} </Formik>
That should fix the showfile update issue and get your conditional validation working as expected!
内容的提问来源于stack exchange,提问作者shubham sourabh

