2

I have an App component and BookList component, which is rendered in App. When I add async to my BookList component I get the following 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 BookList (at App.js:18)
    in div (at App.js:16)
    in ApolloProvider (at App.js:15)
    in App (at src/index.js:16)
    in StrictMode (at src/index.js:14) 

App:

import React from 'react';
import styled from 'styled-components';
import BookList from './components/BookList';
import ApolloClient from 'apollo-boost';
import { ApolloProvider } from '@apollo/react-hooks';

export const client = new ApolloClient({
  uri: 'http://localhost:4001/graphql',
})

const App = () => {
  return (
    <ApolloProvider client={client}>
      <div id='main'>
        <h1>Javed's Reading List</h1>
        <BookList />
      </div>
    </ApolloProvider>
  );
}

export default App;

BookList:

const BookList = async () => {

  const query = gql`
    query {
      books {
        name
        id
      }
    }
  `;

  const { data } = await client.query({ query })
  return (
    <div id='main'>
      <ul id='book-list'>
        <li>Book Name</li>
      </ul>
    </div>
  );
};

export default BookList;

I understand adding async causes the return value to be a promise, but I've done this in the past without any issues. I'm not sure what I'm missing. Why can't I render BookList?

EDIT:

I followed the advice of @MorKadosh and the useEffect hook is not firing on page load

const BookList = () => {
  const [data, setData] = useState(null)

  useEffect(() => {
    const fetch = async () => {
      const response = await client.query({ query });
      console.log(response.data);
      console.log('hello')
      setData(response.data);
    }
    fetch();
  }, [])

  return (
    <div id='main'>
      <ul id='book-list'>
        <li>Book Name</li>
      </ul>
    </div>
  );
};

export default BookList;
MorKadosh
  • 5,846
  • 3
  • 25
  • 37
javedb
  • 228
  • 2
  • 12
  • 1
    Does this answer your question? [Using async/await inside a React functional component](https://stackoverflow.com/questions/57847626/using-async-await-inside-a-react-functional-component) – Daniel Rearden May 18 '20 at 13:44

2 Answers2

3

You shouldn't do that. Instead, use useEffect and useState hooks to fetch your data:

  const [data, setData] = useState(null);

  useEffect(() => {
    const query = ...
    const fetch = async () => {
       const response = await client.query({ query });
       setData(response.data);
    };
    fetch();
  }, []);

This is just example, adjust it for your own needs.

Why you shouldn't do that? because as you said correctly, using async will always return a Promise which is not a valid react component.

MorKadosh
  • 5,846
  • 3
  • 25
  • 37
  • I did this and for some reason the useEffect hook is not firing. Do you know why this is? I updated my question to show the updated code. – javedb May 18 '20 at 14:51
  • @javedb try to `console.log` before and after `fetch`. nothing happens? – MorKadosh May 18 '20 at 14:56
  • no errors whatsoever? tried adding another `useEffect` that simply does a console.log? – MorKadosh May 18 '20 at 15:00
  • I found out it was because i did `uri: 'https://localhost:4001/graphql'`when it needed to be `http`. At first there was no error and then after a few minutes the page wouldnt load anymore. it was very strange. – javedb May 18 '20 at 17:02
0

I think that happens the promise doesn't match with react interface

Why didn't you wrap your API call in an async function or use the useEffect hook?

const apiCall = async () => await client.query(...)
djornada
  • 13
  • 2