Resolving a fetch promise and passing result to a non-await function

Viewed 39

I've a function that returns data from a Postgresql database and returns the data. What should happen is that the data is read from async function getCat() and passed to const Catalogue where the data should be processed and return'd to a ReactJS component.

catalogue.tsx:

import React, { useState } from 'react';
import './mainarea.css';
import './catalogue.css';
import { response } from 'express';
import { invItem } from './invItem';
//import {invItem} from './invItem.js';

const options = {
    method: 'GET',
    mode: 'cors' as RequestMode,
    headers: {'Content-Type': 'application/json'},
};

const getCat = async () => {
    try {
    const res = await fetch(IP_ADDR, options);
    const Data = await res.json();
    return Data;
    } catch {
        console.log("error");
    }
}

const Catalogue = async (props: any) => {
    const invData = await getCat();                    //line 25
    const invCount = invData.length;
    console.log(invData);
    console.log(invCount);
}

export {
    Catalogue,
}

(IP_ADDR isn't the actual variable there, I just wrote that to conceal the address).

The Data is returned from async getCat() just fine, but only if const Catalogue remains an async function. If I remove the async keyword from Catalogue() and the await from the calling of getCat() on line 25, the following error is invoked:

Property 'length' does not exist on type 'Promise<any>'.

Furthermore, if I retain the two aforementioned async and await, process the data as I need to, and return

return (
    <React.Component>
        <div className='invItem'>
            {invItem}
        </div>
    </React.Component>
)

from const Catalogue, to another component Header (posted below, if necessary) the following error is elicited:

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

Is this just an issue of a promise not being resolved the way TypeScript should resolve it? I don't understand what's going on here.

header.tsx:

import { render } from '@testing-library/react';
import React, {useState} from 'react';
import './header.css';
import {About} from './about';
import {Submissions} from './submissions';
import {Contact} from './contact';
import {Catalogue} from './catalogue';

const Header = ({setComponentToRender} : any) => {

    return (
        <div className="tapheader">
            <button className='headerItem' onClick={() => setComponentToRender(About)}>About</button>
            <button className='headerItem' onClick={() => setComponentToRender(Submissions)}>Submissions</button>
            <button className='headerItem' onClick={() => setComponentToRender(Contact)}>Contact</button>
            <button className='headerItem'>Follow</button>
            <button className='headerItem' onClick={() => setComponentToRender(Catalogue)}>Catalogue</button>        
        </div>
    )
}
1 Answers

Your Catalogue seems to be a React component - in this case, making it async won't work indeed.

To make await getCat(); work as you expect, you'll need to combine a couple of hooks: useState and useEffect i.e. in this way:

function Catalogue(props) {
  const [cat, setCat] = useState();
  // runs once on first render
  useEffect(() => {
    const run = async () => {
      const fetchedCat = await getCat();
      setCat(fetchedCat);
    };
    run();
  }, []);
  // here, your `cat` will be undefined at first but will become a value you expect shortly after `await getCat()` is resolved
  ...
}
Related