How to get URL from firebase storage/react native - reactjs

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

Related

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);
};

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?

Image Picker - save uri with Hook

I have a little problem with saving my uri of a picture I have chosen in my react native app.
The following code sample is crucial:
const ProfileScreen = props =>{
const [pickedImage, setPickedImage] = useState(null);
const [modalVisible, setModalVisible] = useState(false); //State for visible Modal
const [userBio, setUserBio] = useState('Useless Placeholder'); //State for users text in the bio
const verifyPermissions = async () => { //ask for permissions on iOS and Android
const result = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (result.status !== 'granted'){
Alert.alert("Insufficient permissions!", "You need to grant galery permissions to customise your profile picture!", [{text: "Got it."}]);
return false;
};
return true;
};
const takeImageHandler = async () => { //function that opens up the camera
const hasPermission = await verifyPermissions();
if (!hasPermission){
return;
}
const image = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
quality: 0.5,
aspect: [16,16]
});
setPickedImage(image.uri);
console.log("Data raw is: " + image.uri);
console.log("Data from hook is: " + pickedImage);
};
if(userBio.length == 0 && modalVisible == false){
setUserBio("Useless Placeholder");
};
As you can see, I have 2 console logs to check my outcome. I want to save the image.uri to my hook I declared at the top of my ProfileScreen. The problem is what I get as an output in my console:
Data raw is:
file:/data/user/0/host.exp.exponent/cache/ExperienceData/%2540kubaguette%252FPigeonBuddy/ImagePicker/30953995-840b-451e-a505-6082df16b9e3.jpg
Data from hook is: null
Why is setPickedImage(image.uri) not working here? Why can I console.log my uri of the chosen picture but not save this uri to my hook and retrieve it?
setPickedImage as any method which updates the state is async by nature.
If this is the only issue, you can track the changes with useEffect.
useEffect(() => {
console.log(pickedImage);
}, [pickedImage]);
You can see the difference here: https://codesandbox.io/s/usestate-async-rnzox?file=/src/App.js

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

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);
};

Firebase storage getImageURL after uploading to after save URL in firestore(React)?

I just want to upload an image then get is URL to save to firestore because i want to save the url of that image to an object. I just want the await to wait for the upload to be finished and then to get the url.
Problem is when i try to get the url it says it doesnt exist but when i go to firebase is there.
const fileData = await fileUpload(imageHome, values.newHomeTeamName);
const url = await storage.ref(fileData).getDownloadURL();
console.log(url);
const fileUpload = async (image: File, newHomeTeamName: string) => {
const fileName = formatFileName(image.name, newHomeTeamName);
const uploadTask = storage.ref(fileName).put(image);
await uploadTask.on(
'state_changed',
snapsphot => {},
error => {
console.log(error);
}
);
return fileName;
};
Your fileUpload function looks a bit unusual to me. You're using await on the on() call, but that doesn't return a promise. What you should do instead is wait on the task itself. So something like:
const fileUpload = async (image: File, newHomeTeamName: string) => {
const fileName = formatFileName(image.name, newHomeTeamName);
const uploadTask = storage.ref(fileName).put(image);
await uploadTask;
return fileName;
}
Or a bit simpler:
const fileUpload = async (image: File, newHomeTeamName: string) => {
const fileName = formatFileName(image.name, newHomeTeamName);
await storage.ref(fileName).put(image);
return fileName;
}
If you want to handle the error, you can catch it in there too. But since all you do is log it, I'd recommend letting it escape and leave it to the runtime to log it.
This is what i did for my app and the url does get stored in the firestore
//imports
import { storage, db } from './firebase'
import firebase from 'firebase'
//states or hooks
const [caption, setCaption] = useState('')
const [image, setImage] = useState(null)
const [progress, setProgress] = useState(0)
const handleUpload=()=>{
const uploadTask = storage.ref(`images/${image.name}`).put(image);
uploadTask.on(
'state_changed',
(snapshot)=>{
const progress = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) *100
);
setProgress(progress)
},
(error)=>{
console.log(error);
alert(error.message);
},
()=>{
storage
.ref('images')
.child(image.name)
.getDownloadURL()
.then(url =>{
db.collection('posts').add({
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
caption: caption,
imageUrl: url,
username: uploadname
});
setImage(null);
setProgress(0);
setCaption("");
})
}
)
}
The handleUpload trigress off when the upload button is clicked

Resources