如何使用 reactjs 将图像上传到 Firebase web v9

How to upload images to Firebase web v9 using reactjs

我在将图像上传到 firebase 但使用网络版本 9 时遇到问题。 我正在关注他正在构建 Facebook 克隆的其中一个平台上的教程。我被困在 firebase 上传图像和文件的这一部分...... 我检查了 firebase 的文档,并试图弄清楚应该更改,但我做不到。 我想要的是将 firebase 代码从旧版本转换为最新的 Web V9。 这是我的代码,但在以前的版本中:

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)

其实一切都在documentation.

里有详细说明

替换uploadTask定义

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

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');

并替换上传监控块,做

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});
    });
  }
);

请注意 UploadTask object behaves like a Promise,并在上传完成时解析其快照数据,因此如果您只对完整事件感兴趣,也可以 uploadTask.then()

如果您的 firebaseConfig 没问题,那么这应该可以!

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();
            };

我遇到了同样的错误,并且能够使用 async await 解决它。我知道这是一个正统的方法,但我成功了。

我使用了与 Renaud Tarnec 相同的逻辑,这就是文档示例所具有的逻辑,但我仍然知道 uploadTask 不是一个函数,很可能是一些异步问题。

请看下面我的例子,你可以很容易地适应你的。

请记住,我没有发现任何错误,但我建议您这样做。

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');

  };

希望这对您或遇到同样问题的任何人有所帮助。

我猜你正在看 Sonny FB clone 卡在了新的 FB 变化中。这个版本适合我。

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 = ""
    }

截至 2021 年 12 月 4 日对我有用

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"
          );
        }
      };

这就是我解决问题的方法。按照上述解决方案,使用 'uploadBytesResumable' 函数意味着我无法渲染我的图像,因为它们以错误的格式返回。我改回 'uploadString' 并将我的代码编辑为如下所示:

  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 = '';
  };