react实现上传
React 实现文件上传
在 React 中实现文件上传功能通常涉及以下几个关键步骤:
创建文件输入组件
使用 <input type="file"> 元素创建文件选择器,通过 onChange 事件获取用户选择的文件。可以通过 useRef 或状态管理来获取文件对象。
const [selectedFile, setSelectedFile] = useState(null);
const handleFileChange = (event) => {
setSelectedFile(event.target.files[0]);
};
return (
<input type="file" onChange={handleFileChange} />
);
处理文件上传
使用 FormData 对象包装文件数据,通过 fetch 或 axios 发送到服务器。需要设置 multipart/form-data 内容类型。
const handleUpload = async () => {
const formData = new FormData();
formData.append('file', selectedFile);
try {
const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
});
console.log('Upload successful:', response);
} catch (error) {
console.error('Upload failed:', error);
}
};
显示上传进度
对于大文件上传,可以通过 axios 的 onUploadProgress 回调显示进度条。
const [uploadProgress, setUploadProgress] = useState(0);
const handleUpload = async () => {
const formData = new FormData();
formData.append('file', selectedFile);
const config = {
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
setUploadProgress(percentCompleted);
},
};
await axios.post('/api/upload', formData, config);
};
添加拖放上传功能
通过 react-dropzone 库实现拖放区域,提升用户体验。
import { useDropzone } from 'react-dropzone';
const { getRootProps, getInputProps } = useDropzone({
onDrop: (acceptedFiles) => {
setSelectedFile(acceptedFiles[0]);
},
});
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>拖放文件到这里,或点击选择文件</p>
</div>
);
文件预览和验证 在上传前预览图像文件或验证文件类型/大小。
const [preview, setPreview] = useState('');
useEffect(() => {
if (!selectedFile) return;
const objectUrl = URL.createObjectURL(selectedFile);
setPreview(objectUrl);
return () => URL.revokeObjectURL(objectUrl);
}, [selectedFile]);
// 验证文件
const isValidFile = selectedFile &&
selectedFile.size < 5 * 1024 * 1024 &&
['image/jpeg', 'image/png'].includes(selectedFile.type);
完整组件示例
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function FileUpload() {
const [file, setFile] = useState(null);
const [preview, setPreview] = useState('');
const [progress, setProgress] = useState(0);
const handleChange = (e) => {
const selected = e.target.files[0];
if (selected && selected.type.match('image.*')) {
setFile(selected);
}
};
const handleSubmit = async () => {
const formData = new FormData();
formData.append('file', file);
try {
await axios.post('/upload', formData, {
onUploadProgress: (progressEvent) => {
setProgress(
Math.round((progressEvent.loaded * 100) / progressEvent.total)
);
},
});
alert('上传成功');
} catch (error) {
console.error('上传失败:', error);
}
};
useEffect(() => {
if (!file) return;
const reader = new FileReader();
reader.onload = () => setPreview(reader.result);
reader.readAsDataURL(file);
}, [file]);
return (
<div>
<input type="file" onChange={handleChange} accept="image/*" />
{preview && <img src={preview} alt="预览" width="200" />}
{file && (
<button onClick={handleSubmit}>
上传 {progress > 0 && `${progress}%`}
</button>
)}
</div>
);
}
export default FileUpload;
服务器端处理
Node.js Express 示例处理上传文件:
const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('file'), (req, res) => {
console.log('文件已接收:', req.file);
res.status(200).json({ message: '文件上传成功' });
});
app.listen(3000, () => console.log('服务器运行中'));






