It seems "images" array is first empty and the elements are added later when data is fetched from firestore - but the React state won't update, so no image is displayed, although I used await everywhere possible.
useEffect(() => {
async function getAllImages() {
const images = await imageStorage.downloadAllImages(true);
// images is first empty and then populated after the html has been rendered
setImages(images);
}
getAllImages();
}, []);
display images:
const handleGetImages = (images) => {
console.log("images", images); // image is first empty and then populated after the html has been rendered
return images.map((imageData) => {
return (
<Grid.Column key={imageData.url}>
<span class="image left">
<img src={imageData.url} style={styles.image} alt="" />
</span>
</Grid.Column>
);
});
};
imageStorage.js
export async function downloadAllImages(thumbnail) {
const imageRef = collection(db, "images");
console.log("hi");
var images = [];
const q = query(imageRef, orderBy("date", "desc"), limit(10));
const querySnapshot = await getDocs(q);
querySnapshot.forEach(async (doc) => {
var imagePath = doc.data().ref; // image/task/...
if (thumbnail) imagePath = imagePath.replace("images", "thumbnails");
// GET metadata of the image
const imageRef = ref(storage, imagePath);
// GET [imagePrefix] URL
const url = await getDownloadURL(imageRef);
const fullMetadata = await getMetadata(imageRef);
images.push({
path: imagePath,
url: url,
metadata: fullMetadata.customMetadata,
});
});
return images;
}
Any way to fix this? Thanks!
CodePudding user response:
Your code is close. Array.prototype.forEach is synchronous though. I suspect your downloadAllImages function isn't waiting for the loop callbacks to complete and returns the images array not populated yet.
Refactor the logic to create an array of Promises (the async callback functions) and await Promise.all them, then you'll have a populated array of images to return.
export async function downloadAllImages(thumbnail) {
const imageRef = collection(db, "images");
const q = query(imageRef, orderBy("date", "desc"), limit(10));
const querySnapshot = await getDocs(q);
// Map querySnapshot docs to array of async functions (Promises)
const imageRequests = querySnapshot.docs.map(async (doc) => {
const imagePath = doc.data().ref; // image/task/...
if (thumbnail) imagePath = imagePath.replace("images", "thumbnails");
// GET metadata of the image
const imageRef = ref(storage, imagePath);
// GET [imagePrefix] URL
const url = await getDownloadURL(imageRef);
const fullMetadata = await getMetadata(imageRef);
// Return image objects
return {
path: imagePath,
url: url,
metadata: fullMetadata.customMetadata,
};
});
// Return array of resolved promises (i.e. the image objects)
return Promise.all(imageRequests);
}
