如何使用Expo Image Picker向AWS批量上传图片
批量上传图片到AWS Amplify的修复方案
核心问题分析
你的代码无法实现批量上传主要有以下几个问题:
- 函数组件错误使用
this关键字,导致方法调用失败 - Expo ImagePicker多选返回的结构是
assets数组,直接遍历pickerResult无效 - Blob对象没有
name属性,上传时文件名会丢失 - 状态更新错误,上传后的图片会被覆盖而非追加到列表
- 部分方法未正确绑定作用域,导致执行报错
修复后的完整代码
import { Amplify, Auth, Storage } from "aws-amplify"; import * as Clipboard from "expo-clipboard"; import * as ImagePicker from "expo-image-picker"; import { useState } from "react"; import { Button, Image, Text, View, StyleSheet } from "react-native"; import awsconfig from "../aws-exports"; Amplify.configure(awsconfig); const UploadImageAWS = () => { const [images, setImages] = useState([]); const [uploadProgress, setUploadProgress] = useState({}); // 选择图片 const pickImage = async () => { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, aspect: [4, 3], quality: 1, allowsMultipleSelection: true, }); if (!result.canceled) { handleImagePicked(result.assets); } }; // 处理选中的图片数组 const handleImagePicked = async (assets) => { try { // 遍历选中的每个图片 for (const asset of assets) { // 生成唯一文件名,避免覆盖 const filename = `${Date.now()}-${Math.random().toString(36).substring(2)}.jpg`; const imgBlob = await fetchImageFromUri(asset.uri); const uploadKey = await uploadImage(filename, imgBlob, filename); const downloadUrl = await Storage.get(uploadKey, { level: "public" }); // 追加图片到列表 setImages(prev => [...prev, downloadUrl]); } } catch (e) { console.error("上传失败", e); alert("上传失败"); } }; // 上传图片到S3 const uploadImage = (filename, imgBlob, key) => { return Storage.put(key, imgBlob, { level: "public", contentType: "image/jpeg", progressCallback(progress) { const percentage = parseInt((progress.loaded / progress.total) * 100); // 更新对应文件的上传进度 setUploadProgress(prev => ({ ...prev, [key]: percentage })); }, }) .then(response => response.key) .catch(error => { console.error("上传错误", error); throw error; }); }; // 从URI获取Blob对象 const fetchImageFromUri = async (uri) => { const response = await fetch(uri); return response.blob(); }; // 复制单个图片URL到剪贴板 const copyToClipboard = (url) => { Clipboard.setString(url); alert("图片URL已复制到剪贴板"); }; return ( <View style={styles.container}> <Text style={styles.title}>AWS Storage 批量上传Demo</Text> {/* 显示每个图片的上传进度 */} {Object.entries(uploadProgress).map(([key, percentage]) => ( percentage < 100 && ( <Text key={key} style={styles.percentage}> 上传中: {percentage}% </Text> ) ))} {/* 显示已上传的图片列表 */} {images.map((imgUrl, index) => ( <View key={index} style={styles.imageContainer}> <Text onPress={() => copyToClipboard(imgUrl)} style={styles.result}> <Image source={{ uri: imgUrl }} style={styles.image} /> </Text> <Text style={styles.info}>点击图片复制URL</Text> </View> ))} <Button onPress={pickImage} title="从相册选择图片" /> </View> ); }; // 样式定义 const styles = StyleSheet.create({ container: { flex: 1, alignItems: "center", justifyContent: "center", paddingTop: 50, paddingHorizontal: 20, }, title: { fontSize: 20, fontWeight: "bold", marginBottom: 20, }, percentage: { fontSize: 16, marginVertical: 10, }, imageContainer: { marginVertical: 15, alignItems: "center", }, image: { width: 250, height: 250, borderRadius: 8, }, result: { marginVertical: 10, }, info: { fontSize: 12, color: "#666", }, }); export default UploadImageAWS;
关键修复点说明
- 移除
this关键字,函数组件内直接定义并调用方法 - 正确处理ImagePicker返回的
assets数组,遍历选中的图片 - 生成唯一文件名,避免S3上的文件覆盖
- 使用函数式更新状态
setImages(prev => [...prev, downloadUrl]),确保图片追加而非替换 - 为每个上传文件单独维护进度,避免批量上传时进度混乱
- 调整复制功能,支持复制单个图片的URL
- 完善错误捕获与日志输出,便于排查问题
内容的提问来源于stack exchange,提问作者Laspeed
相关产品推荐
相关产品推荐

