【问题标题】:My download URL in my firebase storage is not transferring to the database我的 Firebase 存储中的下载 URL 未传输到数据库
【发布时间】:2022-01-23 08:41:02
【问题描述】:

我正在使用 React 和 Firebase。我正在尝试将图像的下载 url 存储到名为“image”的状态,然后使用该状态添加到正在创建的帖子中的“imageurl”字段。 更新图像状态似乎没有问题,但是当我查看在我的 firebase 数据库中创建的新帖子对象中的“imageurl”字段时,它是空的。代码如下:

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;

【问题讨论】:

    标签: reactjs google-cloud-firestore firebase-storage


    【解决方案1】:

    您应该使用状态来触发对 UI 的更新,并使用其他同步原语来确定何时更新数据库。


    例如,在最简单的情况下,您可以在获得下载 URL 时从嵌套侦听器中调用 createPost

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

    您可能需要将 downloadURL 和其他要写入数据的值传递给 createPost 调用,这是不使用 React 的状态来管理数据库更新的另一种情况。


    或者,您可以使用Promises 和/或async/await 来同步调用。

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

    【讨论】:

      【解决方案2】:

      上传文件需要一段时间。所以最好在上传完成后调用create post。

          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('');  if still need the state for some reason 
          
              const postsCollectionRef = collection(db, 'Posts');
          
              const formHandler = (e) => {
                e.preventDefault();
                const file = e.target[0].files[0];
                uploadFiles(file);
              };
            
              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) => { createPost(downloadURL);
                      });
                  }
                );
              };
          
              const createPost = async (imageUrl) => {
               // setImage(imageURL); if still need the state for some reason 
                  const datetime = format(new Date(), 'MMMM dd, yyyy');
                  const post = await addDoc(postsCollectionRef, {
                      caption: caption,
                      imageurl: imageUrl,
                      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;
      

      【讨论】:

        【解决方案3】:

        或者,只需在您的代码中更改一件事,它也可以正常工作,因为上传功能具有异步操作,您在完成上传后调用 createpost 并将下载 URL 传递给 createPost 像这样

        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 [image, setImage] = useState('');
        
            const [caption, setCaption] = useState('');
            const [progress, setProgress] = useState(0);
        
            const postsCollectionRef = collection(db, 'Posts');
        
            const formHandler = (e) => {
              e.preventDefault();
              const file = e.target[0].files[0];
              uploadFiles(file);
            };
          
            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(downloadURL)
                    });
                }
              );
            };
        
            const createPost = async (url) => {
                const datetime = format(new Date(), 'MMMM dd, yyyy');
                const post = await addDoc(postsCollectionRef, {
                    caption: caption,
                    imageurl: url,
                    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;
        

        【讨论】:

          猜你喜欢
          • 2019-12-10
          • 2017-12-11
          • 2018-08-09
          • 1970-01-01
          • 2019-01-06
          • 2020-12-05
          • 2021-10-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多