0

Why when I added await inside for-loop, it will throw me error? How should I fix it?

export default async function DetailsViewer({
}) {

  const galleryList = [];
  const metadata = []

  const [data, setData] = useState()


  useEffect(() => {

    const getNFTDetails = async () => {
      fetch("http://localhost:4000/getDetails").then(response => {
        return response.json()
      })
        .then(posts => {
          setData(posts)

        })
        .then((err) => {
          console.log(err);
        })
    }
    getNFTDetails()
  }, []);

  for (const a in data) {
    metadata[a] = await fetchIPFSJSON(data[a].uri);
    if (metadata[a].image) {
      metadata[a].image = makeGatewayURL(metadata[a].image);
    }
    galleryList.push(
      <Card
        style={{ width: 200 }}
        key={data[a].name}
        title={
          <div>
            {data[a].name}{" "}
            <a
              target="_blank"
              rel="noreferrer"
            >
              {/* <LinkOutlined /> */}
            </a>
          </div>
        }
      >
        <img src={data[a].image} style={{ maxWidth: 130 }} />
      </Card>,
    );
  }
  return (

    <div style={{ maxWidth: 820, margin: "auto", marginTop: 32, paddingBottom: 256 }}>

      <StackGrid columnWidth={200} gutterWidth={16} gutterHeight={16}>
        {galleryList}
      </StackGrid>
    </div>
  )
}

Error

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. in NFTViewer (at App.jsx:271) in Route (at App.jsx:270) in Switch (at App.jsx:261) in Router (created by BrowserRouter) in BrowserRouter (at App.jsx:242) in div (at App.jsx:239) in App (at src/index.jsx:25) in ThemeSwitcherProvider (at src/index.jsx:24) in ApolloProvider (at src/index.jsx:2

Tony
  • 2,515
  • 14
  • 38
  • 71
  • `found: [object Promise]` Seems you are getting a promise. I think you need to resolve before using in JSX. [This](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) might help you. – mc-user Dec 30 '22 at 07:03
  • @mc-user I got this error after I add `async` in the function – Tony Dec 30 '22 at 07:10

2 Answers2

3

You should declare a separate async function that triggers when data changes.
Also, galleryList should be a state so the page will re-render when it populates:

export default function DetailsViewer({}) {
  const metadata = {};

  const [galleryList, setGalleryList] = useState([]);
  const [data, setData] = useState([]);

  useEffect(() => {
    const getNFTDetails = async () => {
      try {
        const response = await fetch('http://localhost:4000/getDetails');
        const posts = await response.json();
        setData(posts);
      } catch (err) {
        console.log(err);
      }
    };
    getNFTDetails();
  }, []);

  useEffect(() => {
    handleData();
  }, [data]);

  const handleData = async () => {
    const list = [];
    for (const a in data) {
      metadata[a] = await fetchIPFSJSON(data[a].uri);
      if (metadata[a].image) {
        metadata[a].image = makeGatewayURL(metadata[a].image);
      }
      list.push(
        <Card
          style={{ width: 200 }}
          key={data[a].name}
          title={
            <div>
              {data[a].name}{' '}
              <a target='_blank' rel='noreferrer'>
                {/* <LinkOutlined /> */}
              </a>
            </div>
          }
        >
          <img src={data[a].image} style={{ maxWidth: 130 }} />
        </Card>
      );
    }
    setGalleryList(list);
  };

  return (
    <div
      style={{
        maxWidth: 820,
        margin: 'auto',
        marginTop: 32,
        paddingBottom: 256,
      }}
    >
      <StackGrid columnWidth={200} gutterWidth={16} gutterHeight={16}>
        {galleryList}
      </StackGrid>
    </div>
  );
}
lpizzinidev
  • 12,741
  • 2
  • 10
  • 29
1
useEffect(() => {

    const createGalleryList= async () => {
      for (const a in data) {
    metadata[a] = await fetchIPFSJSON(data[a].uri);
    if (metadata[a].image) {
      metadata[a].image = makeGatewayURL(metadata[a].image);
    }
    galleryList.push(
      <Card
        style={{ width: 200 }}
        key={data[a].name}
        title={
          <div>
            {data[a].name}{" "}
            <a
              target="_blank"
              rel="noreferrer"
            >
              {/* <LinkOutlined /> */}
            </a>
          </div>
        }
      >
        <img src={data[a].image} style={{ maxWidth: 130 }} />
      </Card>,
    );
  }
    }
    createGalleryList()
  }, [data]);

Create new useEffect and call the galleryList creation variable whenever data is changed. Don't use async in default functions and await in open. use galleryList as state var, at it renders when changed.

Ethan Hunt
  • 136
  • 5