skip to Main Content

Here is what I have tryed to create.

const getPostImgSrc = async (postImg) => {
    const imgRef = ref(storage, `postsImgs/${postImg}`);

    getDownloadURL(imgRef).then((url) => {
       return <img src={url} alt="" />
    });
};

However, the problem is that when I searched the web, it seems like the url is unable to render in time since in async it’s still processing which in turn returns me an img with a src=[object promise]. However when I remove the async it dosen’t work since it needs that async otherwised it would be an error.

So I’m wondering if there is a way to get the url from the getDownloadURL() with or without async? Here is what I’m trying to do with the function, for each post someone has created with an image, get that img url and pass it through in which returns an img element with that src.

<div className="post-details">
      <p>{post.text}</p>

      {post.img === null ? (
          <></>
          ) : (
            getPostImgSrc(post.img)
      )}
</div>

Thanks in advance 🙂

2

Answers


  1. I think what happens is that you a re mixing two ways of handling Promises, the async/await way and the then/catch way. If you are using then/catch then you don’t need to be inside an async function, on the other side, if you are inside an async function then you should be using the await keyword when handling promises and not the then method.

    So instead of:

    getDownloadURL(imgRef).then((url) => {
      return <img src={url} alt="" />
    });
    

    Let’s use await since you already are using an async function:

    const getPostImgSrc = async (postImg) => {
      const imgRef = ref(storage, `postsImgs/${postImg}`);    
      const res = await getDownloadURL(imgRef);
    };
    

    This function now is getting the image url properly, but we have a little issue now, because it is an async function, and all async functions always return a Promise, our getPostImgSrc is returning Promise<undefined>, no matter what you return from an async function it will always be wrapped inside a Promise (in this case the value is undefined beacuse we are not even explicitly returning a value) and as you may know Promises are just objects, so this is why you are getting:

    Uncaught Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

    Because here:

    <div className="post-details">
          <p>{post.text}</p>
    
          {post.img === null ? (
              <></>
              ) : (
                getPostImgSrc(post.img) // <---- here
          )}
    </div>
    

    You are trying to render the value that getPostImgSrc returns (which will always be a Promise since this is an async function, which is an object).

    To fix this we first need to return explicity the image url we are getting in getPostImgSrc:

    const getPostImgSrc = async (postImg) => {
      //... firebase code here 
      const res = await getDownloadURL(imgRef);
      return res;
    };
    

    Then we need a place to store that value, we will use useState for that.

    Then we need to call getPostImgSrc from another place in our component. Because I don’t know how your component code is structured I will call it as soon as the component is rendered, that is using useEffect without dependencies.

    import { useState, useEffect } from 'react';
    
    // inside the component
    const MyComponent = () => {
      const [ imageUrl, setImageUrl ] = useState()
    
      // other component code lines here
    
      useEffect(() => {
        async function callFunction () {
           const url = await getPostImgSrc(post.img)
           setImageUrl(url)
        }
        callFunction();
      }, [])
    
    }
    

    Finally in the JSX part we put the img tag directly:

    <div className="post-details">
          <p>{post.text}</p>
    
          {post.img === null ? (
              <></>
              ) : (
                <img src={imageUrl} alt="" /> // <---- here
          )}
    </div>
    
    Login or Signup to reply.
  2. The problem with your code is that getDownloadURL is an asynchronous function that returns a Promise. You need to use async/await or .then() to handle the result of the Promise.

    const getPostImgSrc = async (postImg) => {
        const imgRef = ref(storage, `postsImgs/${postImg}`);
        const url = await getDownloadURL(imgRef);
        
        return <img src={url} alt="" />;
    };
    

    Then in your post-details component, you can call the getPostImgSrc function to render the image.

    <div className="post-details">
        <p>{post.text}</p>
    
        {post.img === null ? (
            <></>
        ) : (
            await getPostImgSrc(post.img)
        )}
    </div>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search