1

I've got a JSON array of objects (items.[{},{},{}]) which I'm mapping as 'item', and am then rendering a JSX image from an URL stored in the property item.volumeInfo.imageLinks.thumbnail. In most cases, 'thumbnail' exists, but sometimes it doesn't (if there's no image), so first I want to check if it exists, and only try to render the image if it does.

When I try to test for undefined (if (item.volumeInfo.imageLinks.thumbnail !== undefined)), I get the error (TypeError): Cannot read property 'thumbnail' of undefined (well yeah, that's why I'm doing the test!)

So I tried using 'in', but now my code just does nothing at all, no error but no render either... any tips?

this.state.jsonArray.map(item => {
  if ('thumbnail' in item) {
    return <img src={item.volumeInfo.imageLinks.thumbnail} />
  }
})
Sammy
  • 63
  • 1
  • 7
  • Does this answer your question? [Test for existence of nested JavaScript object key](https://stackoverflow.com/questions/2631001/test-for-existence-of-nested-javascript-object-key) – Emile Bergeron Jun 25 '21 at 23:31

2 Answers2

2

(TypeError): Cannot read property 'thumbnail' of undefined means that on some item you are mapping that item.volumeInfo.imageLinks is undefined.

So I tried using 'in', but now my code just does nothing at all, no error but no render either...

This is because the thumbnail property would be in the item.volumeInfo.imageLinks object, not the root item object, so this condition is always false and nothing is returned from the map callback.

I would filter first by items that have the thumbnail property, then map. Don't forget to include a React key (anything but the array index will work so long as it's unique among data) so if/when the mapped state updates that rerendering will work.

this.state.jsonArray
  .filter(item => item.volumeInfo?.imageLinks?.thumbnail)
  .map(item => (
    <img key={item.id} src={item.volumeInfo.imageLinks.thumbnail} />
  ))

If you are unable to use Optional Chaining then use the conventional null checks.

this.state.jsonArray
  .filter(item => {
    return item.volumeInfo &&
      item.volumeInfo.imageLinks &&
      item.volumeInfo.imageLinks.thumbnail;
  })
  .map(item => (
    <img key={item.id} src={item.volumeInfo.imageLinks.thumbnail} />
  ))
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
1

Use the Optional chaining operator (?.)

   this.state.jsonArray.map(item => {
   if (item?.volumeInfo?.imageLinks?.thumbnail) {
    return <img src={item?.volumeInfo?.imageLinks?.thumbnail} />
   }
})

The optional chaining will return undefined if any property of the item is undefined.

Gilbish Kosma
  • 739
  • 5
  • 13