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>