React-Hook-Form刷新后文件输入加载失败,提交时文件重置问题求助
解决React Hook Form文件字段从sessionStorage加载后提交校验失败的问题
问题根源
原生<input type="file">受浏览器安全限制,无法通过代码直接设置其选中的文件(包括通过React Hook Form的defaultValues传入File对象)。你之前的写法里,虽然把dataURL转成了File对象并设为默认值,但真实的文件输入框并没有绑定这个文件,提交时表单会读取输入框的真实值(空FileList),导致必填校验不通过。
解决方案
通过自定义标记+校验逻辑绕过原生限制,同时保留sessionStorage的持久化效果:
调整useForm初始化逻辑
去掉异步defaultValues里的文件处理,改用标记位判断是否有保存的图片,初始化时给文件字段设一个占位值避免校验失败:const getInfoFormData = JSON.parse(sessionStorage.getItem('infoFormData')); const hasSavedImg = !!getInfoFormData?.img; const { register, handleSubmit, formState: { errors, isValid }, setValue, getValues } = useForm({ mode: 'all', defaultValues: { firstName: getInfoFormData?.firstName || '', lastName: getInfoFormData?.lastName || '', aboutMe: getInfoFormData?.aboutMe || '', email: getInfoFormData?.email || '', mobile: getInfoFormData?.mobile || '' } }); // 初始化时标记已保存的图片 useEffect(() => { if (hasSavedImg) { setValue('img', 'saved'); } }, [hasSavedImg, setValue]);修改文件输入的校验规则
自定义校验逻辑,允许占位值'saved'通过校验:<input type='file' id='upload' onChange={(event) => getImgValueFromInput(event)} {...register('img', { required: 'ატვირთეთ ფოტო', validate: (value) => { // 允许保存标记或真实选中的文件 return value === 'saved' || (value instanceof FileList && value.length > 0); } })} />更新文件选择逻辑
选中新文件时,将其转成dataURL保存到sessionStorage,并更新表单值为真实的FileList:const getImgValueFromInput = (event) => { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { const formData = { ...getValues(), img: e.target.result }; sessionStorage.setItem('infoFormData', JSON.stringify(formData)); setValue('img', event.target.files); }; reader.readAsDataURL(file); };提交时处理文件数据
根据表单值判断是使用保存的dataURL还是新上传的文件:const onSubmit = async (data) => { let submitImg; if (data.img === 'saved') { // 把保存的dataURL转回File对象 submitImg = await dataURLtoFile(getInfoFormData.img, 'avatar.png'); } else { submitImg = data.img[0]; } const finalSubmitData = { ...data, img: submitImg }; // 执行你的提交逻辑 };优化展示(可选)
显示已保存的图片预览,并修改按钮文案:<div className='info-img'> <label className={errors.img?.message ? 'error' : ' '}>პირადი ფოტოს ატვირთვა</label> {hasSavedImg && ( <img src={getInfoFormData.img} alt="პირადი ფოტო" className="preview" /> )} <label className='input' htmlFor='upload'> {hasSavedImg ? 'შეცვალე ფოტო' : 'ატვირთვა'} </label> {/* 文件输入框 */} </div>
内容的提问来源于stack exchange,提问作者Killa
相关产品推荐
相关产品推荐

