I am getting this error when I compile my react application: TypeError: Cannot read properties of undefined (reading 'comments').
The part of the code that's causing this is the line 85 of my Dishdetailcomponent.js
Dishdetailcomponent.js
import { Card, CardImg, CardImgOverlay, CardText, CardBody,
CardTitle } from 'reactstrap';
class DishDetail extends Component {
constructor(props) {
super(props);
}
componentDidMount(){
console.log('Dishdetail componentDidMount is invoked');
}
componentDidUpdate(){
console.log('Dishdetail componentDidMount is invoked');
}
componentWillReceiveProps(props) {
this.setState({ props: props })
}
renderDish(dish) {
if (dish != null)
return(
<Card>
<CardImg top src={dish.image} alt={dish.name} />
<CardBody>
<CardTitle>{dish.name}</CardTitle>
<CardText>{dish.description}</CardText>
</CardBody>
</Card>
);
else
return(
<div></div>
);
}
renderComments(comments){
console.log(comments);
var commentsL = {}
if (comments != null){
commentsL = comments.map((comments) => {
return (
<ul class="list">
<uli class="list-item" id = {comments.id}>
<div className="row">
{comments.comment}
</div>
<div className="row">
<p>--</p>{comments.author} {new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: '2-digit'}).format(new Date(Date.parse(comments.date)))}
</div>
</uli>
</ul>
);
}); }
if (comments != null)
return(
<div>
<h4>Comments</h4>
{commentsL}
</div>
);
else
return(
<div></div>
);
}
render() {
console.log(this.props);
console.log('Dishdetail component render is invoked');
if (this.props != 'undefined')
return (
<div className="container">
<div className="row">
<div className="col-12 col-md-5 m-1">
{this.renderDish(this.props.dish)}
</div>
<div className="col-12 col-md-5 m-1">
{this.renderComments(this.props.dish.comments)}
</div>
</div>
</div>
);
}
}
export default DishDetail;
The component above is the presentation component that should show the selected dish at the end of the page.
Maincomponent.js
import { Navbar, NavbarBrand } from 'reactstrap';
import Menu from './MenuComponent';
import DishDetail from './DishdetailComponent';
import { DISHES } from '../shared/dishes';
class Main extends Component {
constructor(props) {
super(props);
this.state = {
dishes: DISHES,
selectedDish: null
};
}
onDishSelect(dishId) {
this.setState({ selectedDish: dishId});
}
render() {
return (
<div>
<Navbar dark color="primary">
<div className="container">
<NavbarBrand href="/">Ristorante Con Fusion</NavbarBrand>
</div>
</Navbar>
<Menu dishes={this.state.dishes} onClick={(dishId) => this.onDishSelect(dishId)} />
<DishDetail dish={this.state.dishes.filter((dish) => dish.id === this.state.selectedDish)[0]} />
</div>
);
}
}
export default Main;
The component above is the container component that passes the props to the Dishdetailcomponent
dishes.js
[
{
id: 0,
name:'Uthappizza',
image: 'assets/images/uthappizza.png',
category: 'mains',
label:'Hot',
price:'4.99',
description:'A unique combination of Indian Uthappam (pancake) and Italian pizza, topped with Cerignola olives, ripe vine cherry tomatoes, Vidalia onion, Guntur chillies and Buffalo Paneer.',
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: 1,
name:'Zucchipakoda',
image: 'assets/images/zucchipakoda.png',
category: 'appetizer',
label:'',
price:'1.99',
description:'Deep fried Zucchini coated with mildly spiced Chickpea flour batter accompanied with a sweet-tangy tamarind sauce',
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: 2,
name:'Vadonut',
image: 'assets/images/vadonut.png',
category: 'appetizer',
label:'New',
price:'1.99',
description:'A quintessential ConFusion experience, is it a vada or is it a donut?',
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: 3,
name:'ElaiCheese Cake',
image: 'assets/images/elaicheesecake.png',
category: 'dessert',
label:'',
price:'2.99',
description:'A delectable, semi-sweet New York Style Cheese Cake, with Graham cracker crust and spiced with Indian cardamoms',
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"
}
]
}
];```
The file above contains the data of the dishes.
Your initial state in Main
is:
this.state = {
dishes: DISHES,
selectedDish: null
};
And you filter the dishes
state into an array and pass the 0th element on to DishDetail
on the dish
prop:
<DishDetail
dish={this.state.dishes.filter((dish) =>
dish.id === this.state.selectedDish)[0]
}
/>
During the initial render cycle the filtering returns an empty array since no dish
item has a null id
property, so the dish
prop is undefined.
Later in the renderComments
of DishDetail
you attempt to pass this.props.dish.comments
:
<div className="col-12 col-md-5 m-1">
{this.renderComments(this.props.dish.comments)}
</div>
Since this.props.dish
is undefined you can't access further into the object.
However you pass a dish
prop you should first check that this.props.dish
and this.props.dish.comments
exist before calling renderComments
.
<div className="col-12 col-md-5 m-1">
{this.props.dish?.comments && this.renderComments(this.props.dish.comments)}
</div>
or
<div className="col-12 col-md-5 m-1">
{this.props.dish
&& this.props.dish.comments
&& this.renderComments(this.props.dish.comments)}
</div>