Hi everyone I have images locally uploaded and I want to upload them to Firebase Storage(which I am successful in uploading ) after that I get their downloadURL with getDownloadURL. since I am going to add multiple images to the collection I need to wait until all downloadURL's are available and.then() I should be using addDoc() method to add new collection documents to firestore. But at the moment I am returning empty state.
const handleAdd = (e) => {
e.preventDefault();
storageImgsRef.map((imgStorageRef) => {
const image = localImages[storageImgsRef.indexOf(imgStorageRef)];
const uploadTask = uploadBytesResumable(imgStorageRef, image);
uploadTask.on(
"state_changed",
(snapshot) => {},
(error) => {
console.log(error);
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((url) => {
setStorageImgsURL((prev) => [...prev, url]);
});
}
);
});
addDoc(shopItemsCol, {
description: description,
discount: discount,
price: price,
title: title,
images: [...storageImgsURL],
});
};
This code successfully adds a new document but with an empty image array. You can see the collection image below
Collection Img URL ; https://drive.google.com/file/d/1XJWe2X0VdMDCXUuOL_u1ShyUEw9ARGvp/view?usp=sharing
CodePudding user response:
Okay after half day here is the solution without setState.Basically, I create an empty array outside of the function and if the mapped array is not on the last index don't add anything to firestore just hold the image URLs with URLs.push(url) until the last index of the array we are mapping.
const [storageImgsRef, setStorageImgsRef] = useState([]);// I couldn't make it work
var URLs = [];
const handleAdd = (e) => {
e.preventDefault();
storageImgsRef.map((imgStorageRef) => {
const image = localImages[storageImgsRef.indexOf(imgStorageRef)];
const uploadTask = uploadBytesResumable(imgStorageRef, image);
uploadTask.on(
"state_changed",
(snapshot) => {},
(error) => {
console.log(error);
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((url) => {
// setStorageImgsURL((prev) => [...prev, url]);
URLs.push(url);
if (
storageImgsRef.length - 1 ==
storageImgsRef.indexOf(imgStorageRef)
) {
addDoc(shopItemsCol, {
description: description,
discount: discount,
price: price,
title: title,
images: [...URLs],
});
}
});
}
);
});
};
I would really appreciate it if anyone comes up with a state solution. Because with the same code state using, state returns an empty array. I don't know if this is something React should work on. Thanks all.
CodePudding user response:
I think the issue is you are setting the state and trying to consume that within the same iteration which means state will not yet have updated. To do this you can probably tweak your code as follows:
const [statusDict, setStatusDict] = useState({});
const statusValues = Object.values(statusDict);
const handleAdd = (e) => {
e.preventDefault();
const statusDict = Object.fromEntries(storageImgsRef.map(
ref => ([ref, null]));
storageImgsRef.map((imgStorageRef) => {
const image =
localImages[storageImgsRef.indexOf(imgStorageRef)];
const uploadTask = uploadBytesResumable(imgStorageRef, image);
uploadTask.on(
"state_changed",
(snapshot) => {},
(error) => {
console.log(error);
},
() => {
getDownloadURL(uploadTask.snapshot.ref).then((url) => {
statusDict[imgStorageRef] = url
});
});
});
};
useEffect(()=> {
if(statusValues.length &&
statusValues.every(value => value !== null)){
addDoc(shopItemsCol, {
description: description,
discount: discount,
price: price,
title: title,
images: [...statusValues],
});
setStatusDict({})
}
}, [statusValues]);