Tinus Wagner
Tinus Wagner

Reputation: 927

Guarding against empty nested arrays in state

I've currently got a little react redux application where I am adding movies, and adding images as a nested array within my object.

What my state looks like after adding an item

{
  movies: [
  0:{
    "title": "asda",
    "director": "asda",
    "genre": "asd",
    "description": "asd",
    "images": [
      {
        "name": "george-michael-306600-2-raw.jpg",
        "type": "image/jpeg",
        "size": "65 kB",
        "base64": "data:image/jpeg;base64,/9j/IMAGE//Z",
        "file": {}
      }
    ],
    "id": "ae04f1e8-18bb-434b-a3e3-b02d44e68d2a"
  }
}

Then I render it in my component as follows

import React from 'react'
import Slider from 'react-slick'
import { dispatch, connect } from 'react-redux'
import {Icon} from 'react-fa'
import { deleteMovie } from '../../actions/movieActions'

import 'slick-carousel/slick/slick.css'
import 'slick-carousel/slick/slick-theme.css'
import './MovieList.scss'

class MovieList extends React.Component{
  constructor(props){
    super (props)
  }

  handleClick(id) {
    dispatch(deleteMovie(id))
  }

  render () {
    // Settings for slick-carousel
    let settings = {
      infinite: true,
      speed: 500
    }


    return (
      <div className='col-lg-12'>
        {this.props.movies.map((b, i) =>
          <div key={i} className="col-lg-2">
            <Slider {...settings}>
              {b.images.map((b, z) =>
                <div className="img-wrapper">
                  <Icon name="trash" className="trash-icon" onClick={(e) =>
                    console.log(this.props.movies[i].id),
                    this.props.onMovieClick.bind(this.props.movies[i].id)
                  }/>
                  <img className="img-responsive" key={z} src={b.base64}></img>
                </div>
              )}
            </Slider>
            <div className="text-left info">
              <h2>{b.title}</h2>
              <p>{b.genre}</p>
            </div>
          </div>
        )}
      </div>
    )
  }
}

// map state from store to props
const mapStateToProps = (state) => {
  return {
    movies: state.movies
  }
};

// Map actions to props
const mapDispatchToProps = (dispatch) => {
  return {
    onMovieClick: (id) => {
      dispatch(deleteMovie(id))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(MovieList)

Now this works perfectly find and my items render as intended until, I try to filter(delete) an item, then my inner loop to make the images into the slider {b.images.map((b, z) fails and i get an error

Cannot read property 'map' of undefined

How can I protect this inner loop from attempting to render items, if array is empty/undefined?

In regular JS I'd simply wrap my map call in a check to see if images is undefined, but how does one address this issue in a JSX render block?

Thanks for your help

Upvotes: 0

Views: 88

Answers (1)

Kyle Muir
Kyle Muir

Reputation: 3925

To protect against it you can use an existence check before doing the map like this:

{b.images && b.images.map((b, z) =>
    <div className="img-wrapper">
        <Icon name="trash" className="trash-icon" onClick={(e) =>
            console.log(this.props.movies[i].id),
            this.props.onMovieClick.bind(this.props.movies[i].id)
        }/>
        <img className="img-responsive" key={z} src={b.base64}></img>
    </div>
)}

b.images will check if b.images is defined and then do the map. Otherwise it will render nothing.

Upvotes: 2

Related Questions