Reputation: 125
I'm trying to upload a set of images to Firebase. The upload itself works, the pictures get added. However, I'd like to get an URL of the pictures.
I figured that I could store them in an Array, but whatever I do, only one picture gets stored in the URL.
I want to A, upload a set of images (max 3) or B, upload only one image. Therefore, I set the target files in a state, and use that state to check if there are one or more images. Then I loop through the upload for x amount of times, and I push the response into ...URL. No matter what I do, I end up with only one image URL in firebase.
Going to try to clarify a bit more: I want to upload up to three images to Firebase (this works, the images gets uploaded into the image-bucket.
What I want, is to get the download URL of the images (I want to use the image URL in another component. Essentially, I want to create an image gallery or an image carousel with the images.
Basically, fetching the image URL from Firebase and display the images.
This is what is displayed in firebase: https://i.sstatic.net/BKkym.jpg
This is a console.log(url): https://i.sstatic.net/2VvL4.jpg
const AddCountryForm = () => {
const [url, setUrl] = useState([]);
const [fileArray, setFileArray] = useState([]);
function onSubmit(e) {
firebase
.firestore()
.collection(continent)
.doc(revName)
.set({
url,
})
.then(() => {
setUrl("");
});
}
const handleChange = (e) => {
setFileArray(e.target.files);
};
const handleUpload = (e) => {
e.preventDefault();
if (fileArray.length > 1) {
for (let i = 0; i < fileArray.length; i++) {
const uploadTask = storage.ref(`images/${fileArray[i].name}`).put(fileArray[i]);
uploadTask.on(
"state_changed",
() => {
storage
.ref("images")
.child(fileArray[i].name)
.getDownloadURL()
.then(res => {
setUrl([...url, res]);
});
}
);
}
}
if (fileArray.length === 1) {
const uploadTask = storage.ref(`images/${fileArray[0].name}`).put(fileArray[0]);
uploadTask.on(
"state_changed",
() => {
storage
.ref("images")
.child(fileArray[0].name)
.getDownloadURL()
.then(res => {
setUrl([res]);
});
}
);
}
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<input type="file" onChange={handleChange} required multiple />
<button onClick={handleUpload}> Upload</button>
</div>
<input type="submit"></input>
</form>
);
};
export default AddCountryForm;
Upvotes: 0
Views: 121
Reputation: 83191
You want to execute several put()
and getDownloadURL()
asynchronous calls to Firebase Storage in parallel.
You have to use Promise.all()
, since put()
returns an UploadTask
(which "behaves like a Promise, and resolves with its snapshot data when the upload completes") and getDownloadURL()
returns a Promise.
Therefore, the following should do the trick:
if (fileArray.length > 1) {
const uploadPromises = [];
for (let i = 0; i < fileArray.length; i++) {
uploadPromises.push(
storage.ref(`images/${fileArray[i].name}`).put(fileArray[i])
);
}
Promise.all(uploadPromises)
.then((uploadTaskSnapshots) => {
const urlPromises = [];
uploadTaskSnapshots.forEach((uploadTaskSnapshot) => {
urlPromises.push(uploadTaskSnapshot.ref.getDownloadURL());
});
return Promise.all(urlPromises);
})
.then((urls) => {
setUrl(urls);
});
}
Upvotes: 2