Theo
Theo

Reputation: 3139

Can not render comments

I have this JSON file:

export const IMAGE_GALLERY = 
[
    {
        id: 0,
        name: 'A nice house',
        image:'assets/images/aristi_1.jpg',
        description: 'A beautiful house. The owner is lucky!',
        comments: [
            {
                id: 0,
                rating: 5,
                comment: "A magnificent view",
                author: "John Lemon",
                date: "2012-10-16T17:57:28.556094Z"
            },
            {
                id: 1,
                rating: 4,
                comment: "I wish I could stay there for a few days",
                author: "Paul McVites",
                date: "2014-09-05T17:57:28.556094Z"
            },
            {
                id: 2,
                rating: 4,
                comment: "Beautiful garden",
                author: "Michael Jaikishan",
                date: "2015-02-13T17:57:28.556094Z"
            },
            {
                id: 3,
                rating: 4,
                comment: "My dream home",
                author: "Ringo Starry",
                date: "2013-12-02T17:57:28.556094Z"
            },
            {
                id: 4,
                rating: 4,
                comment: "Magnificent architecture",
                author: "25 Cent",
                date: "2011-12-02T17:57:28.556094Z"
            },
        ]
    },
    {
        id: 1,
        name: 'Vikos Canyon',
        image:'assets/images/aristi_2.jpg',
        description: 'A magnificent view of Vikos Canyon',
        comments: [
            {
                id: 0,
                rating: 5,
                comment: "Wonderful!",
                author: "John Lemon",
                date: "2012-10-16T17:57:28.556094Z"
            },
            {
                id: 1,
                rating: 4,
                comment: "Splendid",
                author: "Paul McVites",
                date: "2014-09-05T17:57:28.556094Z"
            },
            {
                id: 2,
                rating: 3,
                comment: "Beautiful garden",
                author: "Michael Jaikishan",
                date: "2015-02-13T17:57:28.556094Z"
            },
            {
                id: 3,
                rating: 4,
                comment: "Nice architecture!",
                author: "Ringo Starry",
                date: "2013-12-02T17:57:28.556094Z"
            },
            {
                id: 4,
                rating: 2,
                comment: "Wow!",
                author: "25 Cent",
                date: "2011-12-02T17:57:28.556094Z"
            }
        ]
    },
    {
        id: 2,
        name: 'Central square',
        image:'assets/images/aristi_3.jpg',
        description: 'The center of Aristi',
        comments: [
            {
                id: 0,
                rating: 5,
                comment: "Wonderful square",
                author: "John Lemon",
                date: "2012-10-16T17:57:28.556094Z"
            },
            {
                id: 1,
                rating: 4,
                comment: "I indeed love aristi",
                author: "Paul McVites",
                date: "2014-09-05T17:57:28.556094Z"
            },
            {
                id: 2,
                rating: 3,
                comment: "Splendid!",
                author: "Michael Jaikishan",
                date: "2015-02-13T17:57:28.556094Z"
            },
            {
                id: 3,
                rating: 4,
                comment: "I am speechless!",
                author: "Ringo Starry",
                date: "2013-12-02T17:57:28.556094Z"
            },
            {
                id: 4,
                rating: 2,
                comment: "I was there it was amazing!",
                author: "25 Cent",
                date: "2011-12-02T17:57:28.556094Z"
            }
        ]
    },
    {
        id: 3,
        name: 'Central square',
        image:'assets/images/aristi_4.jpg',
        description: 'Another view of the village\'s center',
        comments: [
            {
                id: 0,
                rating: 5,
                comment: "Imagine all the eatables, living in conFusion!",
                author: "John Lemon",
                date: "2012-10-16T17:57:28.556094Z"
            },
            {
                id: 1,
                rating: 4,
                comment: "Sends anyone to heaven, I wish I could get my mother-in-law to eat it!",
                author: "Paul McVites",
                date: "2014-09-05T17:57:28.556094Z"
             },
             {
                id: 2,
                rating: 3,
                comment: "Eat it, just eat it!",
                author: "Michael Jaikishan",
                date: "2015-02-13T17:57:28.556094Z"
            },
            {
                id: 3,
                rating: 4,
                comment: "Ultimate, Reaching for the stars!",
                author: "Ringo Starry",
                date: "2013-12-02T17:57:28.556094Z"
            },
            {
                id: 4,
                rating: 2,
                comment: "It's your birthday, we're gonna party!",
                author: "25 Cent",
                date: "2011-12-02T17:57:28.556094Z"
            }
        ]
    },
    {
        id: 4,
        name: 'A wonderful image.',
        image:'assets/images/aristi_5.jpg',
        description: 'A green paradise before Easter Day',
        comments: []
    },
    {
        id: 5,
        name: 'From the camera of a drone',
        image:'assets/images/aristi_6.jpg',
        description: 'An overview of the village from the camera of a drone',
        comments: []
    },
    {
        id: 6,
        name: 'Aristi Resort',
        image:'assets/images/aristi_7.jpg',
        description: 'The Aristi Resort hotel',
        comments: []
    },
    {
        id: 7,
        name: 'Elias Guest House',
        image:'assets/images/aristi_8.jpg',
        description: 'The Guest House Elias',
        comments: []
    },
        
]

and want to render some of its elements.

So here is my main component.

import React from 'react';
import { Navbar, NavbarBrand } from 'reactstrap';
import Gallery from './components/GalleryComponent';
import { IMAGE_GALLERY } from "./shared/image_gallery";

class App extends React.Component {

  constructor(props) {
    super(props)

    this.state = {
      image_gallery: IMAGE_GALLERY
    }
  }

  render() {
    return (
      <div className="App">
       <Navbar style={{backgroundColor: '#378248'}}>
          <div className="container">
            <NavbarBrand style={{color: '#fff'}} href="/">I love Aristi</NavbarBrand>
          </div>
       </Navbar> 
       <Gallery image_gallery={this.state.image_gallery} />
      </div>
    );
  }
}

export default App;

As you can see I am setting the IMAGE_GALLERY array as the state of my component. Next, I am passing this state down (as props) to the Gallery component.

import React, { Component } from 'react';
import { Card, CardImg, CardImgOverlay, CardText, CardBody, CardTitle } from 'reactstrap';
import GalleryDetail from './GalleryDetailComponent';

class Gallery extends Component {

    constructor(props) {
        super(props)

        this.state = {
           selectedImage: null
        }
    }


    onDishSelect(gallery) {
        this.setState({
            selectedImage: gallery
        })
    }

    render() {

        const gallery = this.props.image_gallery.map((gallery) => {
            return (
                <div key={gallery.id} className="col-12 col-md-5">
                    <Card onClick={() => this.onDishSelect(gallery)}>
                        <CardImg width="100%" src={gallery.image} alt={gallery.name}/>
                        <CardImgOverlay body className="ml-5" style={{
                                position: 'absolute',
                                right: '45px',
                                }}>
                            <CardTitle style={{
                                backgroundColor: '#378248', 
                                color:"#fff", 
                                textAlign: 'center', 
                                border: '1px solid black' }}>{gallery.name}</CardTitle>
                        </CardImgOverlay>
                    </Card>
                </div>
            )
        })


        return (
           <div className="container">
               <div className="row">
                   {gallery}
               </div>
            <GalleryDetail gallery_image={this.state.selectedImage} />
           </div>
        );
    }
}

export default Gallery;

I can display the images with the appropriate title on top of them. Now when I click an image, I want to display again the image, its title, description, and comments. To do that I am passing down the state to another Component called GalleryDetail.

import React, { Component } from 'react';
import { Card, CardImg, CardText, CardBody, CardTitle } from 'reactstrap';

class GalleryDetail extends Component {

    convertDateToCommentDateFormat(timestamp) {
        const date = new Date(timestamp);
        return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
    }

    renderImage(gallery){
        
        if(gallery !== null) {
            return (
                <Card>
                    <CardImg withd="100%" src={gallery.image} alt={gallery.name}></CardImg>
                    <CardBody>
                        <CardTitle><h3>{gallery.name}</h3></CardTitle>
                        <CardText>{gallery.description}</CardText>
                    </CardBody>
                </Card>
            )
        } else {
            return (
                <div>

                </div>
            )
        }
    }

    renderComments(comments) {
        if (comments == null || comments.length === 0) {
          return (
            <div></div>
          );
        }
    
        const renderedComments = comments.map((comment) => {
          return (
            <li>
              <p>{comment.comment}</p>
              <p>-- {comment.author}, {this.convertDateToCommentDateFormat(comment.date)}</p>
            </li>
          );
        });
    
        return (
          <div>
            <h4>Comments</h4>
            <ul className="list-unstyled">
              { renderedComments }
            </ul>
          </div>
        );
      }
        

    render() {
        return(
            <div class="row">
                <div className="col-12 col-md-5 m-1">
                    { this.renderImage(this.props.gallery_image) }
                </div>
                <div className="col-12 col-md-5 m-1">
                    { this.renderComments(this.props.gallery_image.comments) }
                </div>
            </div>
        )
    }
}

export default GalleryDetail;

I can read everything apart from the comment. I am getting

Uncaught TypeError: Cannot read property 'comments' of null

in

{ this.renderComments(this.props.gallery_image.comments) }

Did I miss something? Why can't I read the comments?

Thanks, Theo.

Upvotes: 0

Views: 68

Answers (1)

norbitrial
norbitrial

Reputation: 15166

You need to handle the null check earlier like the following:

{ this.renderComments(this.props.gallery_image ? this.props.gallery_image.comments : null) }

It failed earlier, technically it means comments does not exists on null. So you need to check first if this.props.gallery_image has any value.

Upvotes: 1

Related Questions