Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

My download URL in my firebase storage is not transferring to the database

I am using React and Firebase. I am trying to store the download url of an image to a state called ‘image’, and then using that state to add to the ‘imageurl’ field in the post being created.
It seems there is no problem with updating the state of the image, but when I look at the ‘imageurl’ field in the new post object created in my firebase database, it is empty. Here’s the code:

import { storage, db } from '../firebase-config';
import { useState } from 'react';
import { ref, getDownloadURL, uploadBytesResumable } from "firebase/storage";
import { collection, addDoc } from 'firebase/firestore';
import { format } from 'date-fns';
const CreatePost = () => {

    const [caption, setCaption] = useState('');
    const [progress, setProgress] = useState(0);
    const [image, setImage] = useState('');

    const postsCollectionRef = collection(db, 'Posts');

    const formHandler = (e) => {
      e.preventDefault();
      const file = e.target[0].files[0];
      uploadFiles(file);
      createPost();
    };
  
    const uploadFiles = (file) => {
      if (!file) return;
      const storageRef = ref(storage, `files/${file.name}`);
      const uploadTask = uploadBytesResumable(storageRef, file);
  
      uploadTask.on(
        "state_changed",
        (snapshot) => {
          const prog = Math.round(
            (snapshot.bytesTransferred / snapshot.totalBytes) * 100
          );
          setProgress(prog);
        },
        (error) => console.log(error),
    
        () => {
            getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
              setImage(downloadURL);
            });
        }
      );
    };

    const createPost = async () => {
        const datetime = format(new Date(), 'MMMM dd, yyyy');
        const post = await addDoc(postsCollectionRef, {
            caption: caption,
            imageurl: image,
            date: datetime
        })
        setCaption('');
    }
  
    return (
      <div>
        <form onSubmit={formHandler}>
          <input type="file" className="input" />
          <button type="submit">Upload</button>
          <input value={caption} type='text' placeholder='caption' onChange={(e) => setCaption(e.target.value)} />
        </form>
        <hr />
        <h2>Uploading done {progress}%</h2>
        <img src={image} />
        <p>{image}</p>
      </div>
    );    
}
export default CreatePost;

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

You should use the state to trigger updates to the UI, and use other synchronization primitives to determine when to update the database.


For example, at its simplest, you can call createPost from within the nested listener when you got the download URL:

const formHandler = (e) => {
  e.preventDefault();
  const file = e.target[0].files[0];
  uploadFiles(file);
  // createPost(); // 👈 don't call this here
};

const uploadFiles = (file) => {
  if (!file) return;
  const storageRef = ref(storage, `files/${file.name}`);
  const uploadTask = uploadBytesResumable(storageRef, file);

  uploadTask.on(
    "state_changed",
    (snapshot) => {
      const prog = Math.round(
        (snapshot.bytesTransferred / snapshot.totalBytes) * 100
      );
      setProgress(prog);
    },
    (error) => console.log(error),

    () => {
        getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
          setImage(downloadURL);
          createPost(); // 👈 but instead call it here
        });
    }
  );
};

You may need to pass the downloadURL and other values you want to write to the data into the createPost call, which is another case of not using React’s state to manage your database updates.


Alternatively, you can use Promises and/or async/await to synchronize the calls.

const formHandler = (e) => {
  e.preventDefault();
  const file = e.target[0].files[0];
  const url = await uploadFiles(file); // 👈 wait for upload to be done
  createPost(url); // 👈 only then create the post with the url
};

                           // 👇 this function is asynchronous, meaning it returns a promise
const uploadFiles = (file) => async {
  if (!file) return;
  const storageRef = ref(storage, `files/${file.name}`);
  const uploadTask = uploadBytesResumable(storageRef, file);

  uploadTask.on(
    "state_changed",
    (snapshot) => {
      const prog = Math.round(
        (snapshot.bytesTransferred / snapshot.totalBytes) * 100
      );
      setProgress(prog);
    },
    (error) => console.log(error)
  );
  await uploadTask; // 👈 uploadTask is a promise itself, so you can await it
  
  let downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
                 // 👆 getDownloadURL returns a promise too, so... yay more await

  return downloadURL; // 👈 return the URL to the caller
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading