Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

MERN: Axios returns data as undefined. Probably issue with async data fetching

I am developing a MERN app which is an online bookstore. I’m using Axios for fetching data from MongoDB. The data is based on several mongoose models that are connected:

Author model: firstName (string), lastName (string), etc., writtenBooks (Book model) which is an array of objects).
Book model: title (string), author (Author model), etc.

There is a page dynamically displaying all the authors – works great. When you click on one of the authors it takes you to a page displaying all the info about this particular author. All the data about the author – firstName, etc. loads fine, until I try to display writtenBooks (which is info from a different model) – then the app breaks, page turns blank.
The error I see in the console is: ‘author.writtenBooks is undefined’

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I’ve seen that there are questions with similar problems and I gathered that the issue is probably the fact that axios is asynchronous so the page loads before the data is fetched and that’s why author returns undefined, but I don’t know what I need to change in my code to make it work. I tried many solutions that helped others, but nothing worked for me.

Can you please help me? 🙂

I’ll just add that author.writtenBooks logs in the console:
// Array(8) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…} ]

  • I can see it when I comment out ‘{author.writtenBooks.map…}’ from the inside of the return section.

Also, all the writtenBooks appear on the page – just as I want them to – if I uncomment that part AFTER loading the page, but the page breaks as soon as I refresh it.

Here’s the screenshot of the Author data – just to show you that writtenBooks have been populated:

author api in the browser

export default function AuthorPage() {
    const { id } = useParams()
    const [author, setAuthor] = useState({});

    useEffect(() => {
        async function getData() {
            const response = await axios.get(`/api/authors/${id}`);
            setAuthor(response.data);
        }
        getData();
    }, []);
   
    console.log(author.writtenBooks)

 return (
      <>
        <SectionTitle title={`${author.firstName} ${author.lastName}`} link="/allauthors" btn="Go Back" />

        <section className='AuthorPage margins mt2'>
            <h4 className='mt1 mb1'>Books available by this author:</h4>

             <ul>
                {/* {author.writtenBooks.map((book) => (
                    <li key={book._id}>&rarr; {book.title}</li>
                ))} */}

                 {/* if you uncomment the code above, the data first loads, then breaks after page refresh */}

            </ul>
        </section>
    </>
    )
}

Here’s code from the controller:



// /api/authors/
const allAuthors = asyncHandler(async (req, res) => {
   const authors = await Author.find({}).sort({ createdAt: -1 })
   res.json(authors)
})

// /api/authors/:id 
const oneAuthor = asyncHandler(async (req, res) => {
   const author = await Author.findOne({ _id: req.params.id })
   .populate('writtenBooks').exec()
   res.json(author)
})

I’ve tried moving getData function outside of useEffect and then call it from inside of it, but, as expected, it doesn’t change anything.
I also tried using fetch instead of axios, but the result is the same.

>Solution :

Not sure but it seems like the issue is when the component renders for the first time, author is an empty object, and you are trying to access author.writtenBooks, which is not yet defined.

try this code:-

export default function AuthorPage() {
    const { id } = useParams();
    const [author, setAuthor] = useState({});

    useEffect(() => {
        async function getData() {
            try {
                const response = await axios.get(`/api/authors/${id}`);
                setAuthor(response.data);
            } catch (error) {
                console.error("Error fetching author data:", error);
            }
        }
        getData();
    }, [id]); // Include id as a dependency

    return (
        <>
            <SectionTitle title={`${author.firstName} ${author.lastName}`} link="/allauthors" btn="Go Back" />

            <section className='AuthorPage margins mt2'>
                <h4 className='mt1 mb1'>Books available by this author:</h4>

                {author.writtenBooks ? (
                    <ul>
                        {author.writtenBooks.map((book) => (
                            <li key={book._id}>&rarr; {book.title}</li>
                        ))}
                    </ul>
                ) : (
                    <p>Loading...</p>
                )}
            </section>
        </>
    );
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading