2

I am having an issue concerning uploading images to firebase but using web version 9. I am following along with a toturial on one of the platforms in which he is building a facebook clone. and I am stuck in this part of firebase uploading images and files... I checked the documentations of firebase and i tried to figure out to should be changed, but I couldn't do it. What I want is to convert the firebase code from the old version to the newest one web V9. This is my code but in the previous version:

import { useSession } from 'next-auth/client';
import { useRef, useState } from 'react';
import { db, storage } from '../firebase';
import firebase from 'firebase';

function InputBox() {
    const [session] = useSession();
    const inputRef = useRef(null);
    const filepickerRef = useRef(null);
    const[imageToPost, setImageToPost] = useState(null);

    const sendPost = (e) => {
        e.preventDefault();

        if (!inputRef.current.value) return;

        db.collection('posts').add({
            message: inputRef.current.value,
            name: session.user.name,
            email: session.user.email,
            image: session.user.image,
            timestamp: firebase.firestore.FieldValue.serverTimestamp()
        }).then(doc => {
            if (imageToPost) {
                const uploadTask = storage.ref(`posts/${doc.id}`).putString(imageToPost, 'data_url')

                removeImage();

                uploadTask.on('state_change', null, error => console.error(error), 
                () => {
                    //When the upload completes
                    storage.ref(`posts`).child(doc.id).getDownloadURL().then(url => {
                        db.collection('posts').doc(doc.id).set({
                            postImage: url
                        },
                        { merge: true}
                        );
                    });
                });
            }
        });

        inputRef.current.value = "";
    };

    const addImageToPost = (e) => {
        const reader = new FileReader();
        if (e.target.files[0]) {
            reader.readAsDataURL(e.target.files[0]);
        }
        reader.onload = (readerEvent) => {
            setImageToPost(readerEvent.target.result);
        };
    };

    const removeImage = () => {
        setImageToPost(null);
    };

    return (here is my jsx)

7 Answers 7

1

if your firebaseConfig is okay, then this should work!

import { setDoc, doc } from "firebase/firestore";
import { ref, uploadString, getDownloadURL, getStorage  } from "firebase/storage";

            if (imageToPost) {
                const storage = getStorage();
                const storageRef = ref(storage, `posts/${docum.id}`);
                const uploadTask = uploadString(storageRef, imageToPost, 'data_url');

                uploadTask.on('state_changed', null,
                (error) => {
                  alert(error);
                },
                () => {
                  getDownloadURL(uploadTask.snapshot.ref)
                  .then((URL) => {
                     setDoc(doc(db, "posts", docum.id), { postImage:URL }, { merge: true});
                  });
                }
              )
              removeImage();
            };
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot but now it is saying "uploadTask is not a function"
change this : replace uploadString with a uploadBytesResumable ==> const uploadTask = uploadBytesResumable(storageRef, imageToPost, 'data_url');
1

this was how I solved the problem. When following the solutions above, using the 'uploadBytesResumable' function meant I couldn't render my images as they came back in the wrong format. I changed back to 'uploadString' and edited my code to look like this:

  const sendPost = async e => {
    e.preventDefault();
    if (!inputRef.current.value) return;

    addDoc(collection(db, 'posts'), {
      message: inputRef.current.value,
      name: session.user.name,
      email: session.user.email,
      image: session.user.image,
      timestamp: serverTimestamp(),
    }).then(docum => {
      if (imageToPost) {
        const storage = getStorage();
        const storageRef = ref(storage, `posts/${docum.id}`);
        uploadString(storageRef, imageToPost, 'data_url').then(snapshot => {
          getDownloadURL(snapshot.ref).then(URL => {
            setDoc(
              doc(db, 'posts', docum.id),
              { postImage: URL },
              { merge: true }
            );
            console.log('File available at ', URL);
          });
          removeImage();
        });
      }
    });

    inputRef.current.value = '';
  };

Comments

1

This code will work guaranteed with firebase v9.

import React, { useRef, useState } from "react";
import Image from "next/image";
import { useSession } from "next-auth/react";
import { EmojiHappyIcon } from "@heroicons/react/outline";
import { CameraIcon, VideoCameraIcon } from "@heroicons/react/solid";
import { db, storage } from "../firebase";
import {
  collection,
  addDoc,
  serverTimestamp,
  doc,
  setDoc,
} from "firebase/firestore";
import { ref, uploadString, getDownloadURL } from "firebase/storage";

function InputBox() {
  const { data: session } = useSession();
  const inputRef = useRef(null);
  const filepickerRef = useRef(null);
  const [imageToPost, setImageToPost] = useState(null);

  const sendPost = (e) => {
    e.preventDefault();
    if (!inputRef.current.value) return;

    addDoc(collection(db, "posts"), {
      message: inputRef.current.value,
      name: session.user.name,
      email: session.user.email,
      image: session.user.image,
      timestamp: serverTimestamp(),
    }).then((document) => {
      if (imageToPost) {
        const storageRef = ref(storage, `posts/${document.id}`);
        uploadString(storageRef, imageToPost, "data_url").then((snapshot) => {
          getDownloadURL(snapshot.ref).then((URL) => {
            setDoc(
              doc(db, "posts", document.id),
              { postImage: URL },
              { merge: true }
            );
            console.log("File available at ", URL);
          });
          removeImage();
        });
      }
    });

    inputRef.current.value = "";
  };

const addImageToPost = (e) => {
    const reader = new FileReader();
    if (e.target.files[0]) {
      reader.readAsDataURL(e.target.files[0]);
    }
    reader.onload = (readerevent) => {
      setImageToPost(readerevent.target.result);
    };
  };

  const removeImage = () => {
    setImageToPost(null);
  };

Comments

0

Actually everything is detailed in the documentation.

To replace the uploadTask definition

const uploadTask = storage.ref(`posts/${doc.id}`).putString(imageToPost, 'data_url')

do

import { getStorage, ref, uploadString, getDownloadURL } from "firebase/storage";

const storage = getStorage();
const storageRef = ref(storage, `posts/${doc.id}`);

const message = 'This is my message.';
const uploadTask = uploadString(storageRef, imageToPost, 'data_url');

and to replace the upload monitoring block, do

import { doc, setDoc } from "firebase/firestore"; 

uploadTask.on('state_changed',
  null
  (error) => {
    // ...
  }, 
  () => {
    getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
       setDoc(doc(db, "posts", doc.id), { postImage: url }, { merge: true});
    });
  }
);

Note that the UploadTask object behaves like a Promise, and resolves with its snapshot data when the upload completes, so you can also do uploadTask.then() if you are just interested by the complete event.

4 Comments

Thanks a lot for your help. Still showing this error again.TypeError: (0 , firebase_firestore__WEBPACK_IMPORTED_MODULE_6__.getStorage) is not a function
Check that Firebase is correctly set. firebase.google.com/docs/web/setup
I am already using for realtime-db so the configuration is 100% correct
I’m sorry but I cannot help you anymore. This error is at the same time extremely generic and very dependent on your own configuration. One would need to see some large parts of your app code to be able to answer.
0

I encountered the same error and was able to work around it using async await. I know it is an orthodox method but I was able to make it work.

I was using the same logic as Renaud Tarnec that is what the Docs examples have but I still got that uploadTask was not a function, most likely some asynchronous issue.

Please see bellow my example, you can easily adapt to yours.

Bear in mind that I did not catch any errors but I do recommend you do it.

const sendPost = async () => {
    // I used uuid package to generate Ids
    const id = uuid();
    const storageRef = ref(storage, `posts/${id}`);

    // I await the uploadTast to finish
    const uploadTask = await uploadString(storageRef, cameraImage, 'data_url');
    

    //than get the url
    const url = await getDownloadURL(uploadTask.ref);

    //finally add the document to the DB
    await setDoc(
      doc(db, 'posts', id),
      {
        imageUrl: url,
        username: 'Apollo',
        read: false,
        //profilePic,
        timestamp: serverTimestamp(),
      },
      { merge: true }
    );
    
    navigate('/chats');

  };

Hopes this is helpful to you or anyone with the same problem.

Comments

0

UPDATED 2022=>

import {
  ref,
  uploadBytesResumable,
  getDownloadURL,
  getStorage,
} from "firebase/storage";

    const uploadPO = async (e) => {
        try {
          if (e.target.files && e.target.files[0]) {
            let reader = new FileReader();
            reader.onload = (e) => {
              poImg.current = e.target.result;
            };
            const file = e.target.files[0];
            reader.readAsDataURL(file);
            setMessage("Uploading...");
            const storage = getStorage();
            const storageRef = ref(storage, `Erogon_Images/${file.name}`);
            const uploadTask = uploadBytesResumable(storageRef, file, "data_url");
    
            uploadTask.on(
              "state_changed",
              (snapshot) => {
                const progress =
                  (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
                setMessage(`Upload is  ${progress}% done`);
              },
              (error) => {
                // Handle unsuccessful uploads
                throw error;
              },
              () => {
                // Handle successful uploads on complete
                // For instance, get the download URL: https://firebasestorage.googleapis.com/...
                getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
                  const body = {
                    rfqID,
                    PO: downloadURL,
                  };
                  Api.post(PATH.updatePO,body).then(()=>{
                     setMessage("Uploaded Successfully");
                  }).catch(err => {
                      console.log(err)
                  })
                });
              }
            );
          }
        } catch (err) {
          console.log(err);
          poImg.current = null;
          setMessage("");
          notifyError(
            err?.message || "Something went wrong while uploading to storage"
          );
        }
      };

Comments

-1

I am guessing you are watching Sonny FB clone was stuck in the new FB changes. This version work for me.

import { collection, addDoc, serverTimestamp, doc, setDoc } from "firebase/firestore";
import { getStorage, ref, uploadBytesResumable, getDownloadURL } from"firebase/storage";
  const sendPost = (e) => {
        e.preventDefault();
        if (!inputRef.current.value) return;
        // Add a new document with a generated id.
        addDoc(collection(db, "posts"), {
            message: inputRef.current.value,
            name: session.user.name,
            email: session.user.email,
            image: session.user.image,
            timestamp: serverTimestamp(),
        }).then(docum => {

            if (imageToPost) {
                const storage = getStorage();
                const storageRef = ref(storage, `posts/${docum.id}`);
                const uploadTask = uploadBytesResumable(storageRef, imageToPost, "data_url");
                removeImage();
                uploadTask.on('state_changed', null,
                    (error) => {
                        console.log(error);
                    },
                    () => {
                        getDownloadURL(uploadTask.snapshot.ref)
                            .then((URL) => {
                                setDoc(doc(db, "posts", docum.id), { postImage: URL }, { merge: true });
                            });
                    }
                )

            };
        });
        inputRef.current.value = ""
    }

This work for me as of 12/4/2021

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.