Home > Software design >  Upload Images to Firestore then Set Formik Field Value
Upload Images to Firestore then Set Formik Field Value

Time:09-27

I am uploading files to Firestore using this custom upload hook I created:

import { storage } from "../firebase/config"
import { ref, getDownloadURL, uploadBytes } from "firebase/storage"

export const useUpload = () => {
    const upload = async (folder, file) => {
        const fileToUpload = ref(storage, `images/${folder}/${file.lastModified   file.name}`)
        const url = await uploadBytes(fileToUpload, file).then(async (snapshot) => {
            const imgURL = await getDownloadURL(snapshot.ref)
            return imgURL
        })
        return url;
    }

    return { upload }
}

I imported the useUpload hook in another file and I'm using it like this:

const {upload} = useUpload()
const previewFiles = (items) => {
        items.map(async (file) => {
            setIsLoading(true)
            await upload('propertyImages', file).then(url => {
                return Object.assign(file, { preview: url })
            })
            setIsLoading(false)
        })
        return items.map(({preview}) => preview)
    }

I use dropzone to process the files so that the users can preview the uploaded files thus:

const { getRootProps, getInputProps } = useDropzone({
        accept: {
            'image/*': []
        },
        onDrop: acceptedFiles => {
            setFiles(previewFiles(acceptedFiles))
        }
    });

Then with this useEffect hook, I set the formik field value:

useEffect(() => {
        formik.setFieldValue("images", files.map(file => (file)))
        return () => files.forEach(file => URL.revokeObjectURL(file));
    }, [files]);

Here's the Formik function:

const formik = useFormik({
        enableReinitialize: true,
        initialValues: {
            images: []
        },
        validationSchema: Yup.object({
            images: Yup.array().min(1, "Please upload at least one image").required()
        }),
        onSubmit: values => {
            console.log(values);
        }
    })

The problem now is that when I submit the Formik form, the images are returning undefined. I tried to return the whole file, instead of returning only the image urls, and they work properly. Here's what I tried:

//To Upload the files
const previewFiles = (items) => {
        items.map(async (file) => {
            setIsLoading(true)
            await upload('propertyImages', file).then(url => {
                return Object.assign(file, { preview: url })
            })
            setIsLoading(false)
        })
        return items
    }

//To Set the formik values
useEffect(() => {
        formik.setFieldValue("images", files.map(file => (file)))
        return () => files.forEach(file => URL.revokeObjectURL(file.preview));
    }, [files]);

This returns the File object with the preview but if I use this useEffect, I get undefined:

useEffect(() => {
        formik.setFieldValue("images", files.map(file => (file.preview)))
        return () => files.forEach(file => URL.revokeObjectURL(file));
    }, [files]);

Please what am I doing wrong? Any help at all would be greatly appreciated as I have been on this issue for many days!

CodePudding user response:

I found out that I could just create a state to hold the values of the urls and set the values as soon as the images are done uploading.

It's something I've always known, I just didn't figure it out in time. So here's the solution I used:

const [urls, setUrls] = useState([])
    const previewFiles = (items) => {
        items.map(async (file) => {
            setIsLoading(true)
            await upload('propertyImages', file).then(url => {
                setUrls(prev => [...prev, url])
                return Object.assign(file, { preview: url })
            })
            formik.setFieldValue("images", urls)
            setIsLoading(false)
        })
        return items
    }

I only modified the previewFiles function.

  • Related