问题描述
我已经使用formik-wizard-form实现了formik多步骤表单。除了文件上传以外,它还可以与其他输入配合使用。
<Form.Group controlId="upload">
<Col>
<div className="form-group files">
Add Attachments:
<input
type="file"
name="upload"
value={values.upload?.files }
onChange={event => {
setFieldValue("upload",event.currentTarget.files);
}}
multiple />
</div>
</Col>
</Form.Group>
控制台日志上传值如下所示。
解决方法
Formik不支持“开箱即用”的文件上传。因此,如果您异步上传文件,则必须执行以下操作:
formData
别忘了将表单数据的其余部分添加到{{1}}。
,根据 docs 使用文件输入的技巧是:
在 React 中,an 始终是不受控制的组件 因为它的值只能由用户设置,不能以编程方式设置。
因此它使用自己的机制以及浏览器的安全实现来设置发送文件的值。出于安全原因,您无法获取发送它的本地计算机上的完整文件路径,尽管我们可以使用 FileReader 对象异步读取文件内容,然后使用结果填充值并将其发送到父表单组件。
有些情况下您可以更改文件输入的值 以编程方式,喜欢 null 以重置您的输入。
在我的多步表单中,我使用了 formik 和 material-ui。它有一个字段 (UploadFiled),其中 type="file"
被自定义字段组件包裹。
每当子组件更新时,文件正在上传,父组件将知道并开始读取指定 Blob 的内容,一旦完成,结果属性包含一个 data: 表示文件数据的 URL 将设置为它的值。它当前接受基于使用 Yup 为其设置的验证的图像。
传统的 application/json 类型不会帮助将图像上传到您的服务器,FormData 会。您需要使用表单数据编写 handleSubmit() 并传递由 Formik 处理的值。
您可以使用 Fetch API 或 Axios 中的任何一个来发送 POST 请求您的服务,取决于您的喜好。
const onSubmit = () => {
// Create an object of formData
const formData = new FormData();
// Update the formData object
formData.append("myFile",file,file.name);
// Details of the uploaded file
console.log(file);
// Request made to the backend api
// Send formData object
axios.post("api/uploadfile",formData);
};
// UploadForm.jsx
import React,{ useState,useEffect } from "react";
import { Field,useField } from "formik";
import { Grid,FormHelperText } from "@material-ui/core";
import UploadField from "../../FormFields/UploadField";
import Thumb from "../Helper/Thumb";
const ImageForm = (props) => {
const {
formField: { image }
} = props;
const [field,meta,helper] = useField(image.name);
const { touched,error } = meta;
const { setValue } = helper;
const isError = touched && error && true;
const { value } = field;
const [fileName,setFileName] = useState(value.name);
const [file,setFile] = useState(value.file);
const [src,setSrc] = useState(value.src);
const _onChange = (e) => {
let reader = new FileReader();
let file = e.target.files[0];
if (file) {
reader.onloadend = () => setFileName(file.name);
if (file.name !== fileName) {
reader.readAsDataURL(file);
setSrc(reader);
setFile(file);
}
}
};
useEffect(() => {
if (file && fileName && src) {
setValue({ file: file,src: src,name: fileName });
console.log(fileName);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
},[src,fileName,file]);
return (
<React.Fragment>
<Grid container spacing={3} justify="center" alignItems="center">
<Grid item xs={12}>
<label>
{image.label}
</label>
<br />
<div
style={{
display: "flex",justifyContent: "flex-start",fontSize: "1.2em"
}}
>
<Field
variant="outlined"
field={field}
component={UploadField}
onChange={_onChange}
isError={isError}
/>
{isError && <FormHelperText color={"red"}>{error}</FormHelperText>}
</div>
</Grid>
<Grid item>{file && src && <Thumb file={file} src={src}></Thumb>}</Grid>
</Grid>
</React.Fragment>
);
};
export default ImageForm;
// UploadField.jsx
import React from "react";
import { Field } from "formik";
const UploadField = ({
field,form: { touched,errors },name,label,isError,...props
}) => {
return (
<>
<Field
variant="outlined"
name="uploader"
title={label}
type={"file"}
{...props}
/>
</>
);
};
export default UploadField;
链接到 Code Sandbox,