reactjs - 如何在formik中创建添加图像输入
问题描述
我想在 formik 中为图像上传创建一个自定义输入字段。我想将二进制文件数据传递给后端,但它正在占用文件位置。你能帮助我吗?
这是样板代码:
import React from 'react';
import { useField } from 'formik';
import { Form, Col, Row } from 'react-bootstrap';
const FileInput = ({ label, ...props }) => {
const [field, meta] = useField(props);
return (
<>
<Form.Group as={Row} controlId="">
<Form.Label htmlFor={props.id || props.name} column sm={3}>
{label}
</Form.Label>
{props.initalImage ? (
<img height="35px" alt={props.initalImage} src={props.initalImage} />
) : null}
<Col sm={4}>
<Form.Control
{...field}
{...props}
accept={props.accept}
isValid={meta.touched && !meta.error}
isInvalid={Boolean(meta.touched && meta.error)}
/>
{meta.error ? (
<>
<Form.Control.Feedback type="invalid">
{meta.error}
</Form.Control.Feedback>
</>
) : null}
<span className="form-text text-muted mt-3">
Please choose an icon which is min. 256x256px.
</span>
</Col>
</Form.Group>
</>
);
};
export { FileInput };
这就是我所说的:
<FileInput
label="Light Icon:"
type="file"
name="lightIcon"
accept="image/x-png"
onBlur
/>
我试过这个,但它不工作:
<FileInput
label="Light Icon:"
type="file"
name="lightIcon"
accept="image/x-png"
onBlur
onChange={(e) => {
setFieldValue('lightIcon', e.target.files[0]);
}}
/>
解决方案
The trick with file inputs is that we shouldn't set it's value, it actually uses it's own mechanism along with browser's security implementations to set it, for security reasons, you can't get the full file path on the local computer of the one sent it, Although we can use a FileReader object to asynchronously read the contents of file and then use the result to fill the value and send it to the parent form component.
There are cases where you can change file input's value programmatically, like to null to reset your input.
There is an UploadFiled with type="file"
get wrapped with a custom Field component, whenever child component getting update, a file is being uploaded, and parent component will knows and starts reading the contents of the specified Blob, once finished, the result attribute contains a data: URL representing the file's data will set as it's value. It currently accepts an image base on the validation that is set for it using Yup.
The traditional application/json type won’t help in uploading the image to your server, the FormData will. You need to write your handleSubmit() using the form data and pass the values handled by Formik.
You can use any from the Fetch API or the Axios for sending the POST request to your serve, depends on you preferences.
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);
};
The link to full Sandbox,
// 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;
推荐阅读
- java - Java程序:程序中异常类的问题,以按顺序对数组进行排序
- c# - OpenXml SDK PowerPoint 朝阳图
- sql - 从其他数据库中按计数 id 获取排序项目
- ruby-on-rails - 在 Mac OS X 10.15 Catalina 上安装 Ruby On Rails 时出错
- sql - 在 sql 中分组结果
- go - 如何在没有任何存储的情况下生成 oidc 状态?
- javascript - 在 React 公共文件夹中存储数据
- python - pip3没有setuplib就不能安装setupdocx,但是没有setupdocx就不能安装setuplib?
- reactjs - 带有 React Hooks 的多模态
- firebase - 是否可以获取 Firebase 中所有用户的 UID 列表?