简体   繁体   中英

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.

So far I've arrived at the following:

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

However, when I use it in my component, I only get promises, and therefore using the returned promise as URL does not work.

I'm calling the hook via the following:

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?

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.

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.

You have to do your side effect logic (awaiting async response in your case) inside the useEffect hook.

Following your intent to do it with promises and async await , your snippet hook should be something like this.

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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