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.