bobypoz
bobypoz

Reputation: 41

Async function inside useMemo not working

I have a situation in which I have an object with all the books and I want to get the author info which sits in a different collection. I tried fetching the data inside a useMemo, but I get an error since the promise does not get resolved I guess. How to make useMemo wait for the data to come for the author?

async function useAuthor(authorID:string) { 
      await firestore.collection('users').doc(authorID).get().then(doc => {
         return doc.data();
    })   
};      

  const normalizedBooks = useMemo(
    () =>
      books?.map( (book) => ({
        ...book,
        author: useAuthor(book.authorId),
      })),
    [books]
  );

Upvotes: 2

Views: 3961

Answers (1)

trixn
trixn

Reputation: 16344

Fetching remote data should be done in an effect:

function useAuthor(authorID:string) { 
    const [author, setAuthor] = useState(null);

    useEffect(() => {
        firestore.collection('users').doc(authorID).get().then(
            doc => setAuthor(doc.data())
        );   
    }, [authorID]);

    return author;
}

Note that author will be null during the first render and until the request completed. You can improve that example by e.g. adding loading and error states. Or you can also use something like react-query which provides those out of the box:

import useQuery from 'react-query';

function getItemById(collectionID:string, itemID:string) {
    return firestore.collection(collectionID).doc(itemID).get().then(
        doc => doc.data()
    );
}

const Author = ({authorID}) => {
    const {data: author, isLoading, error} = useQuery(
        ['users', authorID], 
        getItemById
    );

    if (isLoading) return 'Loading...'

    if (error) return 'Failed to fetch author :(';

    return <p>{author.name}</p>;
}

Upvotes: 1

Related Questions