1

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>
    )
}
  • You need to call `getCat()` from an effect, not from the rendering, and you need to render some placeholder until the http request is finished. – Bergi May 15 '22 at 18:55

1 Answers1

0

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
  ...
}
Igor Loskutov
  • 2,157
  • 2
  • 20
  • 33
  • Thank you for the response, @Igor. Unfortunately, after implementing the solution you provided, the following error is received: `Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app` The error expands to `throwInvalidHookError` `useState` Any ideas? I've scoured Google for hours to no avail. – Jeremy Marino May 16 '22 at 02:25
  • How do you use your `Catalogue`? From the question I assumed it's a component to be used like `` – Igor Loskutov May 16 '22 at 02:38
  • It's used in a button, like the other functions in `header.tsx`. Except that, as I troubleshoot `Catalogue`, I only have it coded as `button className='headerItem' onClick={Catalogue}>Catalogue`, so the errors in console.log are more precise. – Jeremy Marino May 16 '22 at 02:39
  • You'll have to use it as ``, otherwise hooks won't work since it's called like a function in `onClick={Catalogue}`, not being wired into React lifecycle this way. – Igor Loskutov May 16 '22 at 02:52
  • Got it. Any recommendations on how to implement it like that while still retaining the clickable button? – Jeremy Marino May 16 '22 at 03:19
  • Just return your `` from the Catalogue function : ) – Igor Loskutov May 16 '22 at 05:44