Having issues uploading an image file to firebase using React-native/Expo - reactjs

Been trying to upload an image to firebase storage but haven't had any luck thus far. So when I pick an image from the library it displays it but after I try on pressing the post button it just gives me an error.
Here's the error I get: https://imgur.com/a/KLSeu34
export default PostScreen = () => {
const [image, setImage] = useState(null);
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3],
width: 300,
height: 400,
quality: 1,
});
if (!result.cancelled) {
console.log("user cancelled image");
setImage(result.uri);
}
};
const submitPost = async () => {
const result = await uploadImage();
console.log("Image Url: ", imageUrl);
};
const uploadImage = async (uri, imageName) => {
const response = await fetch(uri);
const blob = await response.blob();
var ref = firebase
.storage()
.ref()
.child("images/" + imageName);
return ref.put(blob);
};

Related

How to get URL from firebase storage/react native

The main thing i want to get when a user selects a photo from their album is to get a url from that photo that i can use in my users db. Putting the url to user document in firebase is working and the ImagePicker is working. My main question is how would i(through firebase storage) get a actual url and not something like this:
250F8B0C-72D3-43D4-9CDA-B7F6D8A11F81.jpg
code:
const [image, setImage] = useState("");
//functions
const pickImage = async () => {
try {
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.canceled) {
auth.currentUser.photoURL = result.uri
setImage(result.uri);
console.log(result.uri)
imgFirebase()
}
{/**
await updateDoc(doc(db, "users", uid, {
photoURL: result.uri.toString()
}))
*/}
}
catch(E) {
alert(E)
}
};
async function imgFirebase () {
const d = await fetch(image)
const dd = await d.blob()
const fileName = image.substring(image.lastIndexOf("/")+1)
console.log(fileName)
const storage = getStorage();
const storageRef = ref(storage, fileName);
uploadBytes(storageRef,dd).then((snapshot) => {
console.log('Uploaded a blob or file!');
});
const httpsReference = ref(storage, 'https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg');
}
storage structure
what the firebase storage looks like:
**note that if i press on the image it actually gives me the url in a new tab...i have tried the getDownloadUrl function from the docs but its also giving me errors with the storage reference
in my imgFirebase function what what i need to get to get just the url of the img/blob that i get from the Image picker/firebase storage

Upload more images from react-native app to firebase

I'm trying to upload multiple images from react-native to firebase. The way I go about this is by using expo image picker multiple - by monstrodev ( see snack.io here )
I've managed to get it to work, and managed to be able to choose multiple photos from the 'improvised' camera roll. They load fine in the add screen, but I cannot find a solution on how to upload them properly.
export default function Add(props) {
const [name, setName] = useState("");
const [photos, setPhotos] = useState(null);
const uploadImage = async () => {
const uri = photos[0].uri; // -> uri is like this because 'media' is an array with objects inside that contain name, type, and uri each, and I only need uri of each oject.
const childPath = `data/${firebase.auth().currentUser.uid}/${Math.random().toString(36)}`;
console.log(childPath);
const response = await fetch(uri);
const blob = await response.blob();
const upload = firebase
.storage()
.ref()
.child(childPath)
.put(blob);
const uploadProgress = snapshot => {
console.log(`transferred: ${snapshot.bytesTransferred}`)
};
const uploadComplete = () => {
upload.snapshot.ref.getDownloadURL().then((snapshot) =>{
addPost(snapshot);
console.log(snapshot);
})
};
const uploadError = snapshot => {
console.log(snapshot);
};
upload.on("state_changed", uploadProgress, uploadError, uploadComplete );
};
const addPost = (downloadURL) => {
firebase.firestore()
.collection("allPosts")
.collection(firebase.auth().currentUser.uid)
.collection('userPosts')
.add({
downloadURL,
name,
}).then((function () {
props.navigation.popToTop()
}))
}
useEffect(() => {
const {params} = props.route;
if(params) {
const {photos} = params;
if(photos) setPhotos(photos)
delete params.photos
}
}, [{photos}]) // This useEffect updates when coming back from the ImageBrowserScreen (can be found in snack.io, it's exactly the same)
The main problem is, let's say, I choose 3 photos. If I console.log(photos) I get this:
Array [
Object {
"name": "name1.JPG",
"type": "image/jpg",
"uri": "file:///name1.jpg",
},
Object {
"name": "name2.JPG",
"type": "image/jpg",
"uri": "file:///name2.jpg",
},
Object {
"name": "name3.JPG",
"type": "image/jpg",
"uri": "file:///name3.jpg",
},
]
The only I could get it to work was this, give exact path to uri (photos[0].uri for example) otherwise get network error. But this only uploads the first object/photo. I also tried to map through the photos state and return all uri's into a single array and use that as const uri, but that obviously didn't work, for uri needs only one string. So I somehow need to run that function for each uri to be able to get a downloadURL and store each of them.
EDIT:
const uploadImage = async (photo) => {
const uri = photo.uri;
const childPath = `data/${
firebase.auth().currentUser.uid
}/${Math.random().toString(36)}`;
console.log(childPath);
const response = await fetch(uri);
const blob = await response.blob();
const snapshot = await firebase.storage().ref().child(childPath).put(blob);
const downloadURL = await snapshot.ref.getDownloadURL();
imgs.push(downloadURL)
};
const uploadPhotos = async () => {
await Promise.all(photos.map(p=>uploadImage(photo)).then(addPost())
};
Can you try it with a loop trough all photos and upload them separately. Idealy using a Promise.all to upload them in parallel:
const addPost = async (downloadURLs) => {
await firebase.firestore()
.collection("allPosts")
.collection(firebase.auth().currentUser.uid)
.collection('userPosts')
.add({
downloadURLs,
name,
})
props.navigation.popToTop()
}
const uploadImage = async (photo) => {
const uri = photo.uri;
const childPath = `data/${
firebase.auth().currentUser.uid
}/${Math.random().toString(36)}`;
console.log(childPath);
const response = await fetch(uri);
const blob = await response.blob();
const snapshot = await firebase.storage().ref().child(childPath).put(blob);
const downloadURL = await snapshot.ref.getDownloadURL();
return downloadURL
};
const uploadPhotos = async () => {
const downloadURLs=await Promise.all(photos.map(p=>uploadImage(photo))
await addPost(downloadURLs);
};

waiting array of urls after uploading images to firebase storage and then stroing it again to firestore

const sendImageToFirebase = (e) => {
const promises = []
const urlsArray = []
// productimage is an array of image files
productImage.forEach((image, i) => {
var storageRef = firebase.storage().ref();
var uploadTask = storageRef.child(`${userDetailsFirebase.uid}/` + Math.random()).put(image);
promises.push(uploadTask.on('state_changed',
(snapshot) => {
},
(error) => {
console.log("error");
},
async () => {
const downloadurl = await uploadTask.snapshot.ref.getDownloadURL()
urlsArray.push(downloadurl)
}
))
})
Promise.all(promises).then(res => {
db.collection("products").doc(idGeneratedforProduct).set(
{
imageURL: urlsArray, //array of image urls
},
).then(e => {
}).catch(error => console.log("Error while sendig items to Firebase"))
})
}
I want to upload a multiple images to firebase storage. Here, sendImagToFirebase is a normal function in reactJs, and productimage is an array of image files. I want to wait for URL for each image files and then store all of them as an array to firestore. I would appreciate your input on how to do it?
You can create a function that receoves the ref and the file and returns the downloadURL. By calling it for each file with a Promise.all you get as result your array of downloadURLs:
const uploadFileAndGetDownloadURL = async (ref, file) => {
const snap = await ref.put(file);
const downloadURL = await snap.ref.getDownloadURL();
return downloadURL;
};
const sendImageToFirebase = async (e) => {
const promises = [];
productImage.forEach((image, i) => {
var storageRef = firebase.storage().ref();
var ref = storageRef.child(`${userDetailsFirebase.uid}/` + Math.random());
promises.push(uploadFileAndGetDownloadURL(ref, image));
});
//Your array with the urls
const urlsArray = await Promise.all(promises);
};

upload multiple images to Cloud Storage through Firebase

I am trying to upload multiple pictures to Cloud Storage through Firebase. I am using expo ImagePicker, which can take multiple images using the camera.
Here is code,
const [image, setImage] = useState([]);
const pickImageOnly = async () => {
let result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
quality: 0.5,
});
if (!result.cancelled) {
setNextImg(true);
setImage((images) => images.concat(result.uri));
}
};
Now, I am trying to store those images in the firestore database. However, only one image is stored in the database, Here is my try.
const uploadImage = async () => {
for (let step = 0; step < image.length; step++) {
const uploadUri = image[step];
let filename = uploadUri.substring(uploadUri.lastIndexOf('/') + 1);
setUploading(true);
setTransferred(0);
const response = await fetch(uploadUri);
const blob = await response.blob();
const storageRef = firebase.storage().ref().child(`${user.email}/images/${filename}`)
const task = storageRef.put(blob);
// Set transferred state
task.on('state_changed', (taskSnapshot) => {
// console.log(
// `${taskSnapshot.bytesTransferred} transferred out of ${taskSnapshot.totalBytes}`,
// );
setTransferred(
Math.round(taskSnapshot.bytesTransferred / taskSnapshot.totalBytes) *
100,
)
})
try {
const ref = await task;
const url = await storageRef.getDownloadURL()
setUploading(false);
setImage(null);
return url;
} catch (e) {
console.log(e);
return null;
}
}
}
How can I store all the images in the database?

React-Native Firebase Image upload Expo

I am trying to upload an image to firebase storage however I am getting the error object Object as shown below
Please may someone help me I have never uploaded an image to firebase and really need assistance . Any help what's so ever will be much appreciated. Thank you sooo much in advance!!!!!
This is my code. I've Initialized firebase as well as my image path postImage works as expected.
const handleSubmit = () => {
if (postImage !== undefined) {
const fileExtention = postImage[0].split('.').pop()
console.log(`EXT ${fileExtention}`)
const fileName = `${uniqid}.${fileExtention} `
const reference = firebase.storage().ref(`Posts/images/${fileName}`)
reference.put(postImage)
.on(
firebase.storage.TaskEvent.STATE_CHANGED,
snapshot => {
console.log(`snapshot ${snapshot.state}`)
console.log(`progress ${(snapshot.bytesTransferred / snapshot.totalBytes) * 100}`)
if (snapshot.state === firebase.storage.TaskState.SUCCESS) {
console.log('Success')
}
},
error => {
unsubscribe()
console.log("image upload failed" + error.toString())
},
() => {
firebase.storage()
.ref(`posts/images/${fileName}`)
.getDownloadURL()
.then((downloadUrl) => {
console.log(`file available at ${downloadUrl}`)
})
}
)
}
}
here a solution
const [image, setImage] = useState(null);
const [uploading, setUploading] = useState('')
useEffect(() => {
getPermission();
}, []);
const getPermission = async () => {
if (Platform.OS !== "web") {
const { status } =
await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== "granted") {
alert("Sorry, we need camera roll permissions to make this work!");
}
}
};
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.cancelled) {
setImage(result.uri);
}
};
const getPictureBlob = (uri) => {
// https://github.com/expo/expo/issues/2402#issuecomment-443726662
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", image, true);
xhr.send(null);
});
};
const uploadImageToBucket = async () => {
let blob;
try {
setUploading(true);
blob = await getPictureBlob(image);
const ref = await storage.ref().child(uuid.v4());
const snapshot = await ref.put(blob);
return await snapshot.ref.getDownloadURL();
} catch (e) {
alert(e.message);
} finally {
blob.close();
setUploading(false);
}
};

Resources