Firebase doc field shows an empty array after using useState()

Advertisements

I’m new to react and I’m trying to make an app, where user can upload multiple images at once, and those images get sent to the firebase storage, and urls of those images get stored in an array inside a doc, so that later on they can be accessed in a different page.

Here is a snippet of my code:

function CreateCarParts({isAuth}) { 
    const [images, setImages] = useState(null); 
    const [imageUrls, setImageUrls] = useState([]);
    
    let navigate = useNavigate();
    
    const postsCollectionRef = collection(db, "CarParts")
    
    useEffect(() => {
        if (!localStorage.getItem('isAuth')){
            navigate("/login");
        };
    }, []);
    
    const uploadImages = async () => {
        if(images === null) return;
        let uniqueFolderName = new Date().getTime().toString();
        const imageList = Array.from(images);
        for(let i = 0; i < imageList.length; i++) {
            const image = imageList[i];
            const imageLinkName = `carParts/${uniqueFolderName}/${image.name}`;
            const imageRef = ref(storage, imageLinkName);
            const snapshot = await uploadBytes(imageRef, image);
            const url = await getDownloadURL(snapshot.ref);
            setImageUrls((prev) => [...prev, url]);
        }
        alert("Images Uploaded");
    };
    
    const createPost = async () => {
        await uploadImages();
        await addDoc(postsCollectionRef, {imageUrls});
        navigate('/carparts');
    };
    return ( 
            <>
                <Form.Control onChange={(event) => {setImages(event.target.files);uploadImages();}} type="file" multiple />
    
                <Button onClick={createPost}> Submit </Button>
    
            </>
        ) 
}
export default CreateCarParts;

The images get sent to the storage, and the doc is created successfully, however the imageUrls array is empty. I can’t figure out why it’s not working, I assume I’m using the useState() incorrectly.

>Solution :

imageUrls won’t be updated in the same render cycle, so calling await addDoc(postsCollectionRef, {imageUrls}); right after await uploadImages(); won’t work

I would store urls in a local array instead

function CreateCarParts({isAuth}) { 
    const [images, setImages] = useState(null);
    
    let navigate = useNavigate();
    
    const postsCollectionRef = collection(db, "CarParts")
    
    useEffect(() => {
        if (!localStorage.getItem('isAuth')){
            navigate("/login");
        };
    }, []);
    
    const uploadImages = async () => {
        if(images === null) return;
        let uniqueFolderName = new Date().getTime().toString();
        const imageList = Array.from(images);
        const urls = [];
        for(let i = 0; i < imageList.length; i++) {
            const image = imageList[i];
            const imageLinkName = `carParts/${uniqueFolderName}/${image.name}`;
            const imageRef = ref(storage, imageLinkName);
            const snapshot = await uploadBytes(imageRef, image);
            const url = await getDownloadURL(snapshot.ref);
            urls.push(url);
        }
        alert("Images Uploaded");
        return urls;
    };
    
    const createPost = async () => {
        const imageUrls = await uploadImages();
        await addDoc(postsCollectionRef, {imageUrls});
        navigate('/carparts');
    };
    return ( 
            <>
                <Form.Control onChange={(event) => {setImages(event.target.files);uploadImages();}} type="file" multiple />
    
                <Button onClick={createPost}> Submit </Button>
    
            </>
        ) 
}
export default CreateCarParts;

Leave a Reply Cancel reply