img src 不通过​​函数加载图像

img src doesn't load image through function

首先,我做了一个沙盒:https://codesandbox.io/s/naughty-almeida-u66mlt?file=/src/App.js

问题是调用函数并返回 url 时请求的图像不显示。

到目前为止我尝试了什么以及结果:

  1. 首先我在querySnapshot.forEach里面添加了getDownloadURL() 并将检索到的 url 推送到路径数组。看起来像 这个:

    useEffect(() => {
        const q = query(collection(db, "gallery"));
        const unsubscribe = onSnapshot(q, (querySnapshot) => {
          const path = [];
          querySnapshot.forEach((doc) => {
            getDownloadURL(ref(storage, doc.data().bild)).then((url) {
              path.push(doc.data(), url);
             })
          });
          console.log(path);
          setPaths(path);
        });
        setLoading(false);
        return unsubscribe;
      }, []);
    

    然后我映射了路径,但图像没有显示。

  2. 我创建了另一个 useState 并调用了函数 getURL(src) querySnapshot.forEach() 里面。在 getURL() 函数中我更新了它 从 getDownloadURL() 检索到 url 的状态。后来我 将状态添加到 src 并且它起作用了。

    但我担心的是,当有不止一张图像时它会失败,我 还没有测试过。

  3. 我将检索到的 url 形式 getDownloadURL 转换为字符串。像这样

    function getURL(src) {...} return String(url) 但这也没有用。

<img /> 使用“alt”文本呈现,所以我认为它与 url.

有关

我不太明白这个问题,希望有人能帮我解决。

您可以将组件拆分成小组件。比方说 Gallery 和 GalleryImage。

GalleryImage 将采用 srcdescription 道具。在此组件中声明一个 imageSrc 状态变量。然后您可以在 useEffect 中进行调用(在 dependencies 数组中使用 src),然后在调用完成时设置 imageSrc 状态。调用 setImageSrc 将触发 re-render.

已更新沙箱:https://codesandbox.io/s/silly-fire-f84e95

从 Firestore 加载数据和下载图像 URL 都是异步操作。在对 path.push(doc.data(), url) 的任何调用发生之前,您正在调用 setPaths(path)

我推荐 运行 调试器中的代码或添加日志记录来验证这一点,因为这是理解如何处理异步 API 的关键。

解决方案始终相同:任何需要异步加载数据的代码都需要数据可用时调用的回调中。

所以在你的情况下,最简单的方法是:

onSnapshot(q, (querySnapshot) => {
  const path = [];
  querySnapshot.forEach((doc) => {
    getDownloadURL(ref(storage, doc.data().bild)).then((url) {
      path.push(doc.data(), url);
      setPaths(path); // 
    })
  });
});

这会在您每次下载时设置路径 URL。


如果您想等到下载完所有文件 URLs 后再设置路径,您可以使用计数器来检查文档数与下载数 URLs,或者您可以使用承诺和 Promise.all:

onSnapshot(q, (querySnapshot) => {
  const promises = querySnapshot.docs.map((doc) => getDownloadURL(ref(storage, doc.data().bild)))
  Promise.all(promises).then((urls) {
    setPaths(urls);
  })
});