在Next.js中用Formik和Yup实现独立组件图片上传验证遇阻求助
问题:Next.js中Formik+Yup图片上传验证失效
我在Next.js应用里尝试通过向独立组件传递handleOnImageChange方法,结合Formik和Yup实现图片上传验证,但验证无法正常生效。试过用useFormikContext也没成功,求解决。
现有代码:
主组件代码:
const validationSchema = yup.object().shape({ file: yup.mixed().required('Please upload an image') }); function handleOnImageChange(event) { const file = event.currentTarget.files[0]; uploadImage(file); } <Formik onSubmit={handleSubmit} initialValues={defaultFormState} validationSchema={validationSchema} > {() => ( <> <div> <Uploader imageSrc={imageSrc} handleOnImageChange={handleOnImageChange} /> <ErrorMessage name="file" component={InputError} /> </div> </> )} </Formik>
Uploader组件代码:
const Uploader = ({handleOnImageChange, imageSrc}) => { return ( <> <input id="file" accept=".jpg, .jpeg, .png, .gif, .webp" name="file" type="file" onChange={handleOnImageChange} /> {imageSrc && ( <img src={imageSrc} width="200"/> )} </> ) }
解决方案
问题根源是Formik的表单状态没有同步更新:你自定义的handleOnImageChange只执行了上传逻辑,但没有把选中的文件同步到Formik的values对象里,导致Yup无法检测到file字段的变化,验证自然不会触发。
方法一:通过props传递Formik的setFieldValue
修改主组件,从Formik的render回调中获取setFieldValue并传给Uploader:
<Formik onSubmit={handleSubmit} initialValues={defaultFormState} validationSchema={validationSchema} > {/* 解构获取setFieldValue */} {({ setFieldValue }) => ( <> <div> <Uploader imageSrc={imageSrc} setFieldValue={setFieldValue} /> <ErrorMessage name="file" component={InputError} /> </div> </> )} </Formik>
然后在Uploader组件中,用setFieldValue更新Formik的file字段:
const Uploader = ({ setFieldValue, imageSrc }) => { const handleOnImageChange = (event) => { const file = event.currentTarget.files[0]; // 关键:同步更新Formik的file字段值 setFieldValue('file', file); // 执行你的上传逻辑 uploadImage(file); }; return ( <> <input id="file" accept=".jpg, .jpeg, .png, .gif, .webp" name="file" type="file" onChange={handleOnImageChange} /> {imageSrc && <img src={imageSrc} width="200"/>} </> ) }
方法二:使用useFormikContext获取Formik方法
如果不想通过props传递,可以在Uploader组件中直接用useFormikContext获取setFieldValue:
import { useFormikContext } from 'formik'; const Uploader = ({ imageSrc }) => { // 从Formik上下文获取setFieldValue const { setFieldValue } = useFormikContext(); const handleOnImageChange = (event) => { const file = event.currentTarget.files[0]; setFieldValue('file', file); uploadImage(file); }; return ( <> <input id="file" accept=".jpg, .jpeg, .png, .gif, .webp" name="file" type="file" onChange={handleOnImageChange} /> {imageSrc && <img src={imageSrc} width="200"/>} </> ) }
额外注意事项
初始化表单值:确保
defaultFormState包含file字段,比如:const defaultFormState = { file: null, // 其他表单字段... };增强Yup验证:可以添加文件类型和大小的校验,让验证更完善:
const validationSchema = yup.object().shape({ file: yup.mixed() .required('请上传图片') .test('fileType', '仅支持jpg/jpeg/png/gif/webp格式', (value) => { if (!value) return true; // 必填验证已经处理空值情况 return ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].includes(value.type); }) .test('fileSize', '图片大小不能超过2MB', (value) => { if (!value) return true; return value.size <= 2 * 1024 * 1024; // 2MB }) });
内容的提问来源于stack exchange,提问作者Dennis
相关产品推荐
相关产品推荐

