介绍
很多APP都会有上传图片或者文件的功能,对于创建一个全栈的APP这是很基础的需求。比如Facebook、Instagram和Snapchat都有上传图片和视频的能力。
在传统的HTML网站,上传文件表单会强制页面刷新,用户可能会感到奇怪。同时,你可能也会想要定制上传表单的样式能和你的APP的整体设计风格保持一致。当谈到这些问题的时候,React可以帮助你提供一个更好的用户体验。这篇指南可以帮助你建立并运行一个包含文件上传的React应用。
创建基础表单
可以参考React官方指南,创建一个React应用,在App.js 中创建一个简单的表单,包含一个name字段和一个文件输入字段。如下:
import React from "react";
const App = () => {
return (
<div className="App">
<form>
<input type="text" />
<input type="file" />
</form>
</div>
);
};
然后在组件中增加state用来存储name字段和文件数据。
import React, { useState } from "react";
const App = () => {
const [name, setName] = useState("");
const [selectedFile, setSelectedFile] = useState(null);
return (
<div className="App">
<form>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<input
type="file"
value={selectedFile}
onChange={(e) => setSelectedFile(e.target.files[0])}
/>
</form>
</div>
);
};
封装自定义上传组件
既然基本的表单已经创建好了,接下来我们可以封装一个自定义的文件上传组件方便后面可以在app中复用到不同的场景。如果你在网页上查看这个表单,你可能会觉得外观并不是那么好看,那是因为浏览器应用的是默认的样式。本节我们将介绍如何创建一个自定义样式的上传组件。
const FileUploader = () => {
const handleFileInput = () => {}
return (
<div className="file-uploader">
<input type="file" onChange={handleFileInput}>
</div>
)
}
为了创建一个自定义文件上传组件,第一步是隐藏默认的输入框,通过ref来触发输入框的click事件
import React, {useRef} from 'react'
const FileUploader = ({onFileSelect}) => {
const fileInput = useRef(null)
const handleFileInput = (e) => {
// handle validations
onFileSelect(e.target.files[0])
}
return (
<div className="file-uploader">
<input ref="fileInput" type="file" onChange={handleFileInput}>
<button onClick={e => fileInput.current && fileInput.current.click()} className="btn btn-primary">
</div>
)
}
你可以给上传按钮增加和你整理应用匹配的样式,将上传的文件通过onchange回调函数回传给父组件函数onFileSelect。在handleFileInput方法中,你还可以增加校验函数,比如校验文件大小,文件扩展名等等。然后可以回调父组件通过pros透传的处理函数onFileSelectSuccess和onFileSelectError等。
const handleFileInput = (e) => {
// handle validations
const file = e.target.files[0];
if (file.size > 1024)
onFileSelectError({ error: "File size cannot exceed more than 1MB" });
else onFileSelectSuccess(file);
};
将上传组件添加到表单
将表单引入上传组件,如下:
import React, { useState } from "react";
const App = () => {
const [name, setName] = useState("");
const [selectedFile, setSelectedFile] = useState(null);
const submitForm = () => {};
return (
<div className="App">
<form>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<FileUploaded
onFileSelectSuccess={(file) => setSelectedFile(file)}
onFileSelectError={({ error }) => alert(error)}
/>
<button onClick={submitForm}>Submit</button>
</form>
</div>
);
};
通过FormData上传文件
可以通过FormData对象来上传文件,通过append方法在FormData对象中追加name和file字段数据。
const submitForm = () => {
const formData = new FormData();
formData.append("name", name);
formData.append("file", selectedFile);
axios
.post(UPLOAD_URL, formData)
.then((res) => {
alert("File Upload success");
})
.catch((err) => alert("File Upload Error"));
};
好了,这里你已经成功的创建了一个自定义上传组件的表单了。
总结
文件上传是web应用的基本功能,你可以使用第三方的类库来实现自定义文件上传,但是你应该有基础的认知了解这些组件的实现原理。当你遇到一些三方组件没办法实现的定制上传场景时,自己定义的上传组件或许能够帮你实现。