加载 Firebase 图像的自定义挂钩 URL

Custom Hook to Load Firebase Image URL

我正在尝试创建一个自定义挂钩,该挂钩将为存储在 Firebase 中的图像加载 URL。

到目前为止,我已经得出以下结论:

useLoadImageURL.js

export default async function useLoadImageURL(projectId, fileName) {
    const [url, setURL] = useState()

    useEffect(() => {
        return url
    }, [url])

    const storage = getStorage(app);
    setURL(await getDownloadURL(ref(storage, `images/projects/${projectId}/${fileName}`)))
}

然而,当我在我的组件中使用它时,我只得到承诺,因此使用返回的承诺作为 URL 不起作用。

我通过以下方式调用挂钩:

ProjectCard.js

export default function ProjectCard({ project }) {
    const coverImageURL = useLoadImageURL(project.id, project.coverImagePath)
    return <img src={coverImageURL} />
}

如何更改挂钩或如何调用它来检索实际 URL?

您可以从您的代码中删除 asyncawait,而不是在挂钩的底部调用 setUrl——这将在每次被调用者组件时启动调用重新呈现——将其包装在 useEffect 中,并在 then 回调中更新状态。

编辑:完整代码:

const storage = getStorage(app); // as app seems to be external to the hook, storage can likely be too

export default function useLoadImageURL(projectId, fileName) {
  const [url, setUrl] = useState();

  useEffect(() => {
    getDownloadURL(ref(storage, `images/projects/${projectId}/${fileName}`))
      .then((value) => {
        setUrl(value); // should work provided getDownloadURL actually is a promise that gives a string
      });
  }, [projectId,fileName]);
  
  return url;
}

这将使 url 状态仅在 projectIdfileName 更改时更改。

您必须在 useEffect 挂钩内执行副作用逻辑(在您的情况下等待异步响应)。

根据您的意图,使用 promises 和 async await,您的代码片段挂钩应该是这样的。

import { useState, useEffect } from "react";

// hook
function useLoadImageURL(filename) {
  const [url, setURL] = useState("some-image-spinner-url");

  // simulating your async api call to firebase service
  const setTimeoutAsync = (cb, delay) =>
    new Promise((resolve) => {
      setTimeout(() => {
        resolve(cb());
      }, delay);
    });

  useEffect(() => {
    async function asyncFn() {
      const url = await setTimeoutAsync(() => filename, 3000);
      setURL(url);
    }
    asyncFn();
  }, [filename]);

  return [url];
}

// main component
function App() {
  const [url] = useLoadImageURL("firebase-file-name-f1");
  return <div> {url} </div>;
}
export default App;