如何使用redux表单上传文件?
尝试上载文件时,无法将正确的值输入存储区。我得到的不是文件内容,而是类似于如何使用redux表单上传文件?,redux,redux-form,Redux,Redux Form,尝试上载文件时,无法将正确的值输入存储区。我得到的不是文件内容,而是类似于{0:{}。 代码如下: const renderInput = field => ( <div> <input {...field.input} type={field.type}/> { field.meta.touched && field.meta.error && <span classNa
{0:{}
。
代码如下:
const renderInput = field => (
<div>
<input {...field.input} type={field.type}/>
{
field.meta.touched &&
field.meta.error &&
<span className={styles.error}>{field.meta.error}</span>
}
</div>
);
render() {
...
<form className={styles.form} onSubmit={handleSubmit(submit)}>
<div className={styles.interface}>
<label>userpic</label>
<Field
name="userpic"
component={renderInput}
type="file"
/>
</div>
<div>
<button type="submit" disabled={submitting}>Submit</button>
<div>
</form>
...
}
const renderInput=field=>(
{
field.meta.touch&&
field.meta.error&&
{field.meta.error}
}
);
render(){
...
用户权限
提交
...
}
我在web上找到的所有示例都是使用redux表单的v5制作的
如何在redux form v6中输入文件?我的redux form输入包装器示例
import React,{Component,PropTypes}来自'React';
从“react Dropzone”导入Dropzone;
从“元素”导入{Form};
从'redux form'导入{Field};
类FileInput扩展组件{
静态类型={
dropzone_选项:PropTypes.object,
meta:PropTypes.object,
标签:PropTypes.string,
classNameLabel:PropTypes.string,
输入:PropTypes.object,
类名:PropTypes.string,
子项:PropTypes.node,
cbFunction:PropTypes.func,
};
静态defaultProps={
类名:“”,
cbFunction:()=>{},
};
render(){
const{className,input:{onChange},dropzone_选项,meta:{error,toucted},label,classnamelab,children,name,cbFunction}=this.props;
返回(
{label&&p className={classnamelab | |'''}>{label}}
{
CBF功能;
一经更改即返回(f);
}}
className=“dropzone输入”
name={name}
>
{儿童}
{错误&&T?错误:“”
);
}
}
导出默认道具=>;
热使用它:
<FileInput
name="add_photo"
label="Others:"
classNameLabel="file-input-label"
className="file-input"
dropzone_options={{
multiple: false,
accept: 'image/*'
}}
>
<span>Add more</span>
</FileInput>
添加更多
呈现预览图像的另一种方法(下面的示例使用React 16+语法,只接受一个图像文件发送到API;但是,通过一些小的调整,它还可以缩放到多个图像和其他输入字段):
工作示例:
工作示例(过时):
之前: 之后:
容器/UploadForm.js
import React, { Component } from "react";
import { Form, Field, reduxForm } from "redux-form";
import DropZoneField from "../components/dropzoneField";
const imageIsRequired = value => (!value ? "Required" : undefined);
class UploadImageForm extends Component {
state = { imageFile: [] };
handleFormSubmit = formProps => {
const fd = new FormData();
fd.append("imageFile", formProps.imageToUpload.file);
// append any additional Redux form fields
// create an AJAX request here with the created formData
alert(JSON.stringify(formProps, null, 4));
};
handleOnDrop = (newImageFile, onChange) => {
const imageFile = {
file: newImageFile[0],
name: newImageFile[0].name,
preview: URL.createObjectURL(newImageFile[0]),
size: newImageFile[0].size
};
this.setState({ imageFile: [imageFile] }, () => onChange(imageFile));
};
resetForm = () => this.setState({ imageFile: [] }, () => this.props.reset());
render = () => (
<div className="app-container">
<h1 className="title">Upload An Image</h1>
<hr />
<Form onSubmit={this.props.handleSubmit(this.handleFormSubmit)}>
<Field
name="imageToUpload"
component={DropZoneField}
type="file"
imagefile={this.state.imageFile}
handleOnDrop={this.handleOnDrop}
validate={[imageIsRequired]}
/>
<button
type="submit"
className="uk-button uk-button-primary uk-button-large"
disabled={this.props.submitting}
>
Submit
</button>
<button
type="button"
className="uk-button uk-button-default uk-button-large"
disabled={this.props.pristine || this.props.submitting}
onClick={this.resetForm}
style={{ float: "right" }}
>
Clear
</button>
</Form>
<div className="clear" />
</div>
);
}
export default reduxForm({ form: "UploadImageForm" })(UploadImageForm);
import React from "react";
import PropTypes from "prop-types";
import DropZone from "react-dropzone";
import ImagePreview from "./imagePreview";
import Placeholder from "./placeholder";
import ShowError from "./showError";
const DropZoneField = ({
handleOnDrop,
input: { onChange },
imagefile,
meta: { error, touched }
}) => (
<div className="preview-container">
<DropZone
accept="image/jpeg, image/png, image/gif, image/bmp"
className="upload-container"
onDrop={file => handleOnDrop(file, onChange)}
>
{({ getRootProps, getInputProps }) =>
imagefile && imagefile.length > 0 ? (
<ImagePreview imagefile={imagefile} />
) : (
<Placeholder
error={error}
touched={touched}
getInputProps={getInputProps}
getRootProps={getRootProps}
/>
)
}
</DropZone>
<ShowError error={error} touched={touched} />
</div>
);
DropZoneField.propTypes = {
error: PropTypes.string,
handleOnDrop: PropTypes.func.isRequired,
imagefile: PropTypes.arrayOf(
PropTypes.shape({
file: PropTypes.file,
name: PropTypes.string,
preview: PropTypes.string,
size: PropTypes.number
})
),
label: PropTypes.string,
onChange: PropTypes.func,
touched: PropTypes.bool
};
export default DropZoneField;
import React from "react";
import PropTypes from "prop-types";
const ImagePreview = ({ imagefile }) =>
imagefile.map(({ name, preview, size }) => (
<div key={name} className="render-preview">
<div className="image-container">
<img src={preview} alt={name} />
</div>
<div className="details">
{name} - {(size / 1024000).toFixed(2)}MB
</div>
</div>
));
ImagePreview.propTypes = {
imagefile: PropTypes.arrayOf(
PropTypes.shape({
file: PropTypes.file,
name: PropTypes.string,
preview: PropTypes.string,
size: PropTypes.number
})
)
};
export default ImagePreview;
import React from "react";
import PropTypes from "prop-types";
import { MdCloudUpload } from "react-icons/md";
const Placeholder = ({ getInputProps, getRootProps, error, touched }) => (
<div
{...getRootProps()}
className={`placeholder-preview ${error && touched ? "has-error" : ""}`}
>
<input {...getInputProps()} />
<MdCloudUpload style={{ fontSize: 100, paddingTop: 85 }} />
<p>Click or drag image file to this area to upload.</p>
</div>
);
Placeholder.propTypes = {
error: PropTypes.string,
getInputProps: PropTypes.func.isRequired,
getRootProps: PropTypes.func.isRequired,
touched: PropTypes.bool
};
export default Placeholder;
import React from "react";
import PropTypes from "prop-types";
import { MdInfoOutline } from "react-icons/md";
const ShowError = ({ error, touched }) =>
touched && error ? (
<div className="error">
<MdInfoOutline
style={{ position: "relative", top: -2, marginRight: 2 }}
/>
{error}
</div>
) : null;
ShowError.propTypes = {
error: PropTypes.string,
touched: PropTypes.bool
};
export default ShowError;
img {
max-height: 240px;
margin: 0 auto;
}
.app-container {
width: 500px;
margin: 30px auto;
}
.clear {
clear: both;
}
.details,
.title {
text-align: center;
}
.error {
margin-top: 4px;
color: red;
}
.has-error {
border: 1px dotted red;
}
.image-container {
align-items: center;
display: flex;
width: 85%;
height: 80%;
float: left;
margin: 15px 10px 10px 37px;
text-align: center;
}
.preview-container {
height: 335px;
width: 100%;
margin-bottom: 40px;
}
.placeholder-preview,
.render-preview {
text-align: center;
background-color: #efebeb;
height: 100%;
width: 100%;
border-radius: 5px;
}
.upload-container {
cursor: pointer;
height: 300px;
}
import React from 'react'
import { useDropzone } from 'react-dropzone'
function MyDropzone(props) {
const onDrop = (filesToUpload) => {
return props.input.onChange(filesToUpload[0]);
}
const onChange = (filesToUpload) => {
return props.input.onChange(filesToUpload[0]);
}
const { getRootProps, getInputProps } = useDropzone({ onDrop });
return (
<div {...getRootProps()}>
<input {...getInputProps()} onChange={e => onChange(e.target.files)} />
<p> Drop or select yout file</p>
</div>
)
}
export default MyDropzone;
<Field
name="myfile"
component={renderFile}
/>
创建一个字段组件,如:
import React, {Component} from 'react'
export default class FieldFileInput extends Component{
constructor(props) {
super(props)
this.onChange = this.onChange.bind(this)
}
onChange(e) {
const { input: { onChange } } = this.props
onChange(e.target.files[0])
}
render(){
const { input: { value } } = this.props
const {input,label, required, meta, } = this.props //whatever props you send to the component from redux-form Field
return(
<div><label>{label}</label>
<div>
<input
type='file'
accept='.jpg, .png, .jpeg'
onChange={this.onChange}
/>
</div>
</div>
)
}
}
import React,{Component}来自“React”
导出默认类FieldFileInput扩展组件{
建造师(道具){
超级(道具)
this.onChange=this.onChange.bind(this)
}
onChange(e){
const{input:{onChange}}=this.props
onChange(e.target.files[0])
}
render(){
const{input:{value}}=this.props
const{input,label,required,meta,}=this.props//从redux表单字段发送到组件的任何props
返回(
{label}
)
}
}
将此组件传递到所需的字段组件。如果您需要一个简单的文件上传功能,则无需额外的Dropzone或其他库 如果您需要base64编码将其发送到后端,以下是一个适用于我的修改版本:
export class FileInput extends React.Component {
getBase64 = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
onFileChange = async (e) => {
const { input } = this.props
const targetFile = e.target.files[0]
if (targetFile) {
const val = await this.getBase64(targetFile)
input.onChange(val)
} else {
input.onChange(null)
}
}
render() {
return (
<input
type="file"
onChange={this.onFileChange}
/>
)
}
}
导出类FileInput扩展React.Component{
getBase64=(文件)=>{
返回新承诺((解决、拒绝)=>{
const reader=new FileReader();
reader.readAsDataURL(文件);
reader.onload=()=>resolve(reader.result);
reader.onerror=错误=>拒绝(错误);
});
}
onFileChange=async(e)=>{
const{input}=this.props
const targetFile=e.target.files[0]
如果(目标文件){
const val=wait this.getBase64(targetFile)
input.onChange(val)
}否则{
input.onChange(null)
}
}
render(){
返回(
)
}
}
然后,字段组件将如下所示:
我成功地在材质ui包装文本字段上使用redux表单,如下所示:
B4编辑:
编辑后:
<Field name="image" component={FileTextField} floatingLabelText={messages.chooseImage} fullWidth={true} />
组件定义为:
const styles = {
button: {
margin: 12
},
exampleImageInput: {
cursor: 'pointer',
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
width: '100%',
opacity: 0
},
FFS:{
position: 'absolute',
lineHeight: '1.5',
top: '38',
transition: 'none',
zIndex: '1',
transform: 'none',
transformOrigin: 'none',
pointerEvents: 'none',
userSelect: 'none',
fontSize: '16',
color: 'rgba(0, 0, 0, 0.8)',
}
};
export const FileTextField = ({
floatingLabelText,
fullWidth,
input,
label,
meta: { touched, error },
...custom })=>{
if (input.value && input.value[0] && input.value[0].name) {
floatingLabelText = input.value[0].name;
}
delete input.value;
return (
<TextField
hintText={label}
fullWidth={fullWidth}
floatingLabelShrinkStyle={styles.FFS}
floatingLabelText={floatingLabelText}
inputStyle={styles.exampleImageInput}
type="file"
errorText={error}
{...input}
{...custom}
/>
)
}
const styles={
按钮:{
差额:12
},
示例图像输入:{
光标:“指针”,
位置:'绝对',
排名:0,
底部:0,
右:0,,
左:0,,
宽度:“100%”,
不透明度:0
},
自由流速度:{
位置:'绝对',
线宽:“1.5”,
前:"38",,
过渡:“无”,
zIndex:'1',
转换:“无”,
transformOrigin:“无”,
pointerEvents:'无',
用户选择:“无”,
字体大小:“16”,
颜色:“rgba(0,0,0,0.8)”,
}
};
导出常量FileTextField=({
浮动标签文本,
全宽,
输入,
标签,
meta:{触摸,错误},
…自定义})=>{
if(input.value&&input.value[0]&&input.value[0].name){
floatingLabelText=input.value[0]。名称;
}
删除输入值;
返回(
)
}
表示React>=16和ReduxForm>=8(测试版本分别为React的16.8.6和8.2.5)
工作如下组件
(解决方案由DarkBitz发布在相关网站上)
constadaptefileeventtovalue=delegate=>e=>delegate(e.target.files[0]);
常量文件输入=({
输入:{value:ommitvalue,onChange,onBlur,…inputProps},
梅塔:梅塔,
…道具
}) => {
返回(
);
};
导出常量文件上传=(道具)=>{
const{handleSubmit}=props;
const onFormSubmit=(数据)=>{
控制台日志(数据);
}
返回(
附件
提交
)
}
带Redux表单
const{handleSubmit}=props;
//制作一个常量文件来保存文件道具。
const file=useRef();
//创建一个函数,将redux表单输入文件值替换为自定义值。
constfileupload=()=>{
//jsx获取文件输入
//更改时存储文件/fil
import React from 'react'
import { useDropzone } from 'react-dropzone'
function MyDropzone(props) {
const onDrop = (filesToUpload) => {
return props.input.onChange(filesToUpload[0]);
}
const onChange = (filesToUpload) => {
return props.input.onChange(filesToUpload[0]);
}
const { getRootProps, getInputProps } = useDropzone({ onDrop });
return (
<div {...getRootProps()}>
<input {...getInputProps()} onChange={e => onChange(e.target.files)} />
<p> Drop or select yout file</p>
</div>
)
}
export default MyDropzone;
<Field
name="myfile"
component={renderFile}
/>