3

I'm new to React/Next and having some difficulty displaying data returned by an API.

Here is the data's structure:

myBooks = {
  reading: [
    {
      title: 'book1',
      cover: 'cover1.jpg'
    }
  ],
  toRead: [
    {
      title: 'book2',
      cover: 'cover2.jpg'
    }
  ],
  read: [
    {
      title: 'book3',
      cover: 'cover3.jpg'
    },
    {
      title: 'book4',
      cover: 'cover4.jpg'
    }
  ]
}

This is how I'd like the data displayed:

Reading:
book1

To Read:
book2

Read:
book3
book4

I'd like this to be dynamic, so if I add another category like "favorites," those books show in their own section with a relevant header.

And here is my attempt to render this data, using nested .map functions:

{Object.keys(myBooks).map(category => {
    <h3>{category}</h3>
    category.map(book => (
        <p>{book.title}</p>
    ))
})}

My rationale:

  1. .map can't be used on an object, so I start by selecting the object's keys, which is what I call category (reading, toRead, read)
  2. Once I display the category, traverse down and list each book associated with that category

The error I am receiving:
TypeError: category.map is not a function

Suggesting that category is not an array, or does not exist. Any help would be greatly appreciated!

1
  • The category variable will be a string - reading, toRead, and read. Commented Dec 27, 2020 at 20:23

3 Answers 3

4

You might want to use Object.entries instead, this will give you access to each element's key and value.

{Object.entries(myBooks).map(([category, books]) => (
    <>
        <h3>{category}</h3>
        {books.map((book) => (
            <p>{book.title}</p>
        ))}
    </>
))}
Sign up to request clarification or add additional context in comments.

Comments

3
  1. the function inside the first map, must return just one JSX element.
  2. category is the key, so to get the value use : myBooks[category]
  3. category.map((book) => <p>{book.title}</p>); is a js statement, it must be between {}, and remove the semi-colon at the end.
{Object.keys(myBooks).map((category) => (
        <>
          <h3>{category}</h3>
          {myBooks[category].map((book) => (
            <p>{book.title}</p>
          ))}
        </>
      ))}

Comments

2

The issue is that the category variable will be each key, which is a string. You should change the category.map to myBooks[category].map()

{Object.keys(myBooks).map(category => {
    <h3>{category}</h3>
    {myBooks[category].map(book => (
        <p>{book.title}</p>
    ))}
})}

Also, in this case, you don't want to use .map(). .map() is used when you want to modify the elements in the array - in this case, you just want to loop through them. Use .forEach() instead

{Object.keys(myBooks).forEach(category => {
    <h3>{category}</h3>
    {myBooks[category].forEach(book => (
        <p>{book.title}</p>
    ))}
})}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.