ReactJS:如何使用 Formik 处理图像/文件上传?
Posted
技术标签:
【中文标题】ReactJS:如何使用 Formik 处理图像/文件上传?【英文标题】:ReactJS: How to handle Image / File upload with Formik? 【发布时间】:2019-10-02 14:56:03 【问题描述】:我正在使用ReactJS
为我的网站设计个人资料页面。
现在我的问题是如何从本地机器上传图像并将其保存到数据库并在个人资料页面中显示它
import React, Component from 'react';
import connect from 'react-redux';
import AccountAction from '../../actions/user/AccountPg1Action';
import Formik, Form, Field, ErrorMessage from 'formik';
import * as Yup from 'yup';
class AccountInfo extends Component
constructor(props)
super(props)
this.state =
currentStep: 1,
userAccountData:
userid: '',
useravtar: '',
attachement_id: '',
handleFileUpload = (event) =>
this.setState(useravtar: event.currentTarget.files[0])
;
handleChange = event =>
const name, value = event.target
this.setState(
[name]: value
)
handleSubmit = event =>
let that = this;
const AccountAction = that.props;
event.preventDefault();
let accountInputs =
userid: 49,
useravtar: that.state.image,
attachement_id: 478,
that.setState(
userAccountData: accountInputs,
)
AccountAction(accountInputs)
AccountInfoView = () =>
console.log(this.state.useravtar)
return (
<section id="account_sec" className="second_form">
<div className="container">
<React.Fragment>
<Formik
initialValues=
file: null,
email: '',
phone: ''
validationSchema=accountInfoSchema
render=(values) =>
return(
<Form onSubmit=this.handleSubmit>
<Step1
currentStep=this.state.currentStep
handleChange=this.handleChange
file= this.state.useravtar
handleFileUpload=this.handleFileUpload
/>
</Form>
);
/>
</React.Fragment>
)
render()
return (
<div>this.authView()</div>
)
function Step1(props)
console.log(props.useravtar)
if (props.currentStep !== 1)
return null
return(
<div className="upload">
<label htmlFor="profile">
<div className="imgbox">
<img src="images/trans_116X116.png" />
<img src=props.useravtar className="absoImg" />
</div>
</label>
<input id="file" name="file" type="file" accept="image/*" onChange=props.handleFileUpload/>
<span className="guide_leb">Add your avatar</span>
</div>
)
当我在 handleChange
中为 event.target.file[0] 操作控制台时,它会以未定义的方式响应。
另外,在handleSubmit
操作中执行console.log(this.state.useravtar)
会显示类似c:/fakepath/imgname.jpg
的路径名
P.S:我有多种形式,所以我在 Step
明智地使用它。我正在使用 Redux Reducer 来存储数据。
我已经提到了this 链接,但我的要求不是这样。
【问题讨论】:
您是否尝试过使用表单数据对象 - developer.mozilla.org/en-US/docs/Web/API/FormData/… @SumanthMadishetty :我使用了 Formik 库,所以我使用了该库中的Field
组件。 jaredpalmer.com/formik
@Taalavya formik 没有文件上传组件,你必须使用html输入并使用formik的`setFieldValue`方法来设置数据
【参考方案1】:
Formik 默认不支持文件上传,但是你可以试试下面的
<input id="file" name="file" type="file" onChange=(event) =>
setFieldValue("file", event.currentTarget.files[0]);
/>
这里"file"
代表您用于保存文件的密钥
在提交时,您可以使用
获取文件的文件名、大小等onSubmit=(values) =>
console.log(
fileName: values.file.name,
type: values.file.type,
size: `$values.file.size bytes`
)
如果要将文件设置为组件状态,则可以使用
onChange=(event) =>
this.setState("file": event.currentTarget.files[0]);
根据您的代码,您必须按以下方式处理文件上传
在 AccountInfo 中添加处理文件上传的函数
handleFileUpload = (event) =>
this.setState(WAHTEVETKEYYOUNEED: event.currentTarget.files[0]);
并将相同的功能传递给 Step1 组件,如下所示
<Step1
currentStep=this.state.currentStep
handleChange=this.handleChange
file= this.state.image
handleFileUpload=this.handleFileUpload
/>
在上传文件的 Step1 组件中,将输入更改为
<input id="file" name="file" type="file" accept="image/*" onChange=props.handleFileUpload/>
如果您需要预览上传的图像,则可以创建一个 blob 并传递与图像源相同的内容,如下所示
<img src=URL.createObjectURL(FILE_OBJECT) />
EDIT-1
由于URL.createObjectURL
方法由于安全问题已被弃用,我们需要将srcObject
用于Media Elements,要使用可以使用ref
来分配srcObject,例如
假设您使用的是类组件,
构造函数
在构造函数中可以使用
constructor(props)
super(props)
this.imageElRef = React.createRef(null)
处理更改功能
handleFileUpload = (event) =>
let reader = new FileReader();
let file = event.target.files[0];
reader.onloadend = () =>
this.setState(
file: reader.result
);
;
reader.readAsDataURL(file);
元素
<img src=this.state.file />
【讨论】:
在哪里定义这个setFieldValue
,它会给我一个未定义的错误,例如:./src/components/user/AccountInfo.jsx Line 266: 'setFieldValue' is not defined no-undef
setFieldValue
是从<Formik />
获取的,参考:jaredpalmer.com/formik/docs/api/…
@Taalavya 如果您想直接存储文件以声明您可以使用我提到的方法
@SumanthMadishetty 是的,但它从 function Step1(props)...
函数中抛出此错误。 prnt.sc/np7gnp
你用props.setState是什么意思...你能用实现更新代码吗【参考方案2】:
您可以使用 Formik 上传单个或多个文件并进行验证,如下所示:
import "./App.css";
import useEffect, useState from "react";
import * as Yup from "yup";
import Formik, Field, Form, ErrorMessage, useField from "formik";
import axios from "axios";
function App()
return (
<Formik
initialValues=
profile: [],
validationSchema=Yup.object(
profile:Yup.array().min(1,"select at least 1 file")
)
onSubmit=(values, props) =>
let data = new FormData();
values.profile.forEach((photo, index) =>
data.append(`photo$index`, values.profile[index]);
);
axios
.post("you_api_for_file_upload", data,
headers:
"Content-Type": "multipart/form-data",
,
)
.then((response) =>
console.log(response);
)
.catch((err) =>
console.log(err);
);
>
(formik) =>
return (
<>
<Form>
<input
id="file"
name="profile"
type="file"
onChange=(event) =>
const files = event.target.files;
let myFiles =Array.from(files);
formik.setFieldValue("profile", myFiles);
multiple
/>
<ErrorMessage name="profile"/>
<button type="submit" disabled=formik.isSubmitting>
Submit
</button>
</Form>
</>
);
</Formik>
);
export default App;
注意:您可以根据需要自定义 min(your choice, "your message")。
validationSchema=Yup.object(
profile:Yup.array().min(1,"select at least 1 file")
)
【讨论】:
输入名称和setFieldValue不能作为同一个值,只有字符串类型才可以使用。对于字符串以外的类型,setFieldValue 必须是不同的键【参考方案3】:这是我使用 Formik 和 Material UI
解决的方法在您的 JS 文件中,只需声明一个变量 avatarPreview 如下所示
const [avatarPreview, setAvatarPreview] = useState('/avatars/default.png');
<Box
display='flex'
textAlign='center'
justifyContent='center'
flexDirection='column'>
<ImageAvatar size='md' src=avatarPreview || user?.avatar />
<Button
variant='contained'
component='label'
startIcon=<CloudUploadIcon />>
Choose Avatar
<input
name='avatar'
accept='image/*'
id='contained-button-file'
type='file'
hidden
onChange=(e) =>
const fileReader = new FileReader();
fileReader.onload = () =>
if (fileReader.readyState === 2)
setFieldValue('avatar', fileReader.result);
setAvatarPreview(fileReader.result);
;
fileReader.readAsDataURL(e.target.files[0]);
/>
</Button>
</Box>
默认预览:
选择头像后:
【讨论】:
【参考方案4】:要使用后端处理 formik 中的文件,您只需添加下面给出的输入(您可以将 avatar 更改为您想要的任何内容):
<input
type="file"
name="avatar"
onChange=(event) =>
setFieldValue('avatar', event.currentTarget.files[0]);
/>
onSubmit 您可以使用值 obj 访问文件,例如 values.avatar。
在服务器端(快速)访问我们使用的文件 req.file 您还必须使用 multer 和 cloudinary 来检测文件以在服务器端处理它
【讨论】:
以上是关于ReactJS:如何使用 Formik 处理图像/文件上传?的主要内容,如果未能解决你的问题,请参考以下文章
reactjs - 如何在formik中将状态值传递给初始值
如何将 react-intl-tel-input 与 formik 集成?
reactjs:使用 reactstrap ui 的带有数据时间选择器的 formik 表单示例
如何使用formik react js在handlesubmit函数中接收选择值?