简体   繁体   English

自定义挂钩加载 Firebase 图片 URL

[英]Custom Hook to Load Firebase Image URL

I'm trying to create a custom hook that will load the URL for an image stored in Firebase.我正在尝试创建一个自定义挂钩,它将为存储在 Firebase 中的图像加载 URL。

So far I've arrived at the following:到目前为止,我已经得出以下结论:

useLoadImageURL.js使用LoadImageURL.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}`)))
}

However, when I use it in my component, I only get promises, and therefore using the returned promise as URL does not work.但是,当我在我的组件中使用它时,我只会得到承诺,因此将返回的 promise 用作 URL 是行不通的。

I'm calling the hook via the following:我通过以下方式调用挂钩:

ProjectCard.js ProjectCard.js

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

How can I change the hook or how I'm calling it to retrieve the actual URL?如何更改挂钩或如何调用它来检索实际的 URL?

You can remove async and await from your code, and instead of calling setUrl at the bottom of your hook -- which would initiate the call every time the callee component rerenders -- wrap it in a useEffect , and update the state in a then callback.您可以从代码中删除asyncawait ,而不是在挂钩底部调用setUrl - 每次被调用方组件重新呈现时都会启动调用 - 将其包装在useEffect中,并在then回调中更新 state .

edit: Full code:编辑:完整代码:

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

This will make the url state only change when projectId or fileName changes.这将使url state 仅在projectIdfileName更改时更改。

You have to do your side effect logic (awaiting async response in your case) inside the useEffect hook.您必须在useEffect挂钩内执行副作用逻辑(在您的情况下等待异步响应)。

Following your intent to do it with promises and async await , your snippet hook should be something like this.按照您使用 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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM