前提
react-native(expo)でInstagramのような画像投稿できる機能を作っております。
firebase strageに画像を保存する機能を作成したのですが、複数枚画像をアップロードすることができませんでした。
画像を複数アップロードするにはどのようにすれば良いでしょうか。
また、アップロード後の画像パスを取得してfirestoreにドキュメントを登録する処理も加えています。
よろしくお願いいたします。
発生している問題・エラーメッセージ
画像の配列をループで処理したが、画像の1枚目しかアップロードされず、当然firestoreにもドキュメントは作成されませんでした。
該当のソースコード
アップロード機能
firebase.ts
1 export const uploadImage = async (uri: string, path: string) => { 2 // uriをblobに変換 3 const localUri = await fetch(uri); 4 const blob = await localUri.blob(); 5 // storageにupload 6 const storage = getStorage(); 7 const strageRef = ref(storage, path); 8 9 let downloadUrl = ""; 10 try { 11 await uploadBytesResumable(strageRef, blob); 12 downloadUrl = await getDownloadURL(strageRef); 13 } catch (err) { 14 console.log(err); 15 } 16 return downloadUrl; 17 };
投稿ページ
CreatePost.tsx
1import React, { useEffect, useState, useContext } from "react"; 2import { StyleSheet, SafeAreaView, View, Image, Alert, FlatList } from "react-native"; 3import { setDoc } from 'firebase/firestore'; 4 5import { createPostRef, uploadImage } from "../lib/firebase"; 6import { MultiplePickImage} from "../lib/multiple-image-picker"; 7import { UserContext } from "../contexts/userContext"; 8import { ReviewsContext } from "../contexts/reviewsContext"; 9import { getExtention } from "../utils/file"; 10 11import { IconButton } from "../components/IconButton"; 12import { TextArea } from "../components/TextArea" 13import { StarInput } from "../components/StarInput" 14import { Button } from "../components/Button" 15import { Loading } from "../components/Loading" 16 17import { NativeStackNavigationProp } from "@react-navigation/native-stack"; 18import { RootStackParamList } from "../types/navigation"; 19import { RouteProp } from "@react-navigation/native"; 20import { serverTimestamp } from "firebase/firestore"; 21import { Post } from "../types/post"; 22 23type Props = { 24 navigation: NativeStackNavigationProp<RootStackParamList, "CreatePost">; 25 route: RouteProp<RootStackParamList, "CreatePost">; 26}; 27 28export const CreatePostScreen: React.FC<Props> = ({ 29 navigation, 30 route, 31}: Props) => { 32 const { post } = route.params; 33 const [text, setText] = useState<string>(""); 34 const [imgUrls, setImgUrls] = useState([]); 35 const [loading, setLoading] = useState<boolean>(false); 36 const { user } = useContext(UserContext); 37 38 useEffect(() => { 39 navigation.setOptions({ 40 headerLeft: () => ( 41 <IconButton name="x" onPress={() => navigation.goBack()} /> 42 ), 43 }); 44 }, [post]); 45 46 const onSubmit = async () => { 47 if(!text || !imgUrls) { 48 Alert.alert("レビューまたは画像がありません"); 49 return; 50 }; 51 52 setLoading(true); 53 let imgs = []; 54 //documentのIDを取得 55 const postDocRef = await createPostRef(); 56 imgUrls.map((img) => { 57 //storageのpathを決定 58 const ext = getExtention(img.uri); 59 const storagePath = `post/${postDocRef.id}/${postDocRef.id}.${ext}`; 60 //画像をstorageにアップロード 61 const downloadUrl = uploadImage(img.uri, storagePath); 62 imgs.push(downloadUrl); 63 }) 64 //postドキュメントを作成 65 const post = { 66 id: postDocRef.id, 67 user: { 68 name: user?.name, 69 id: user?.id, 70 imgUrl: user?.imgUrl 71 }, 72 text, 73 imgUrl: imgs, 74 updateAt: serverTimestamp(), 75 createdAt: serverTimestamp(), 76 } as Post; 77 await setDoc(postDocRef,post); 78 79 setLoading(false); 80 navigation.goBack(); 81 }; 82 83 const onPickImage = async () => { 84 const images = await MultiplePickImage(); 85 setImgUrls(images); 86 }; 87 return( 88 <SafeAreaView style={styles.container}> 89 <StarInput score={score} onChangeScore={(value) => setScore(value)} /> 90 <TextArea value={text} onChangeText={(value) => setText(value)} label="" placeholder="キャプションを書く" /> 91 <View style={styles.photoContainer}> 92 <IconButton name="camera" onPress={onPickImage} color="#ccc" /> 93 {!!imgUrls && 94 <FlatList 95 data={imgUrls} 96 keyExtractor={(item, index) => index.toString()} 97 numColumns={2} 98 99 renderItem={({ item }) => ( 100 <View> 101 <Image 102 source={{ uri: item.uri }} 103 style={styles.image} 104 /> 105 </View> 106 )} 107 />} 108 </View> 109 <Button text="投稿する" onPress={onSubmit} /> 110 <Loading visible={loading} /> 111 </SafeAreaView> 112 ); 113}; 114 115const styles = StyleSheet.create({ 116 container: { 117 flex: 1, 118 backgroundColor: "#fff", 119 }, 120 photoContainer: { 121 margin: 8 122 }, 123 image: { 124 width: 100, 125 height: 100, 126 margin: 8 127 } 128});
補足情報(FW/ツールのバージョンなど)
firebase: 9.9.2
expo: 46.0.0
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。