I am struggling and in need of help! I'm extremely new to React - and I'm busy doing this practice assignment for a course that I'm taking to learn it, but I am running into the same sort of problem over and over again and I cannot seem to get it right.
I do not need you to complete my assignment, but any hint or directions/feedback on my code on where I am going wrong and what I am doing wrong would be highly appreciated. Oof, I'm just so tired of not finding the solution on Google/forums, and my React skills are fairly novice so I can't really identify the problem without the help of some super cool React experts out there! Thank you very much in advance. :)
I keep on getting the error: TypeError: Cannot read property 'map' of undefined
Full Source Code Here: https://github.com/christinec-dev/react_new
The overall end goal of my application is as follows (added here for perspective reasons):
Task 1:
Task 2:
Task 3:
----------------------------------------- menuComponent.js
//package imports
import React, { Component } from 'react';
//import bootrap components from reactstrap library
//NOTE: The media query returns a CSS style
import { Card, CardImgOverlay, CardImg, CardBody, CardText, CardTitle } from 'reactstrap';
import DishDetail from './DishdetailComponent';
//creates Menu component
class Menu extends Component {
//define a constructor for it
constructor(props) {
//Props is read-only and are used to pass data, whereas state is for managing data and can be modified by its own component
//required when you create a component in react
super(props);
//when document is loaded no card has been selected by default
this.state = {
selectedDish: null
};
}
//when dishg is clicked, it will render details of dish
onDishSelect(dish) {
this.setState({selectedDish: dish});
}
//if dish is clicked it will show card details, else nothing
renderDish(dish) {
if(dish != null) {
return(
<Card>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardBody>
<CardTitle>{dish.name}</CardTitle>
<CardText>{dish.description}</CardText>
</CardBody>
</Card>
);
} else {
return(
<div></div>
)
}
}
//return a value or function that will be called
render() {
//will iterate (map) over the dishes list and return each key (item) uniquely
const menu = this.props.dishes.map((dish) => {
// This will create the layout of the menu items by displaying the image, name and -description- of each menu item
return (
<div key={dish.id} className="col-12 col-md-5 m-1">
{/* When clicked on, it will run event function*/}
<Card onClick={() => this.onDishSelect(dish.id, dish.comments)}>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardImgOverlay body className="ml-5">
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
);
});
return (
//This will return a menu list that will be defined
<div className="container">
<div className="row">
{/* This will return the menu items */}
{menu}
</div>
<div className="row">
{/* This will return the clicked card dish items when clicked */}
<div className="col-12 col-md-5 m-1">
{this.renderDish(this.state.selectedDish)},
</div>
<div className="col-12 col-md-5 m-1">
<DishDetail dishes={this.state.dishes} />
</div>
</div>
</div>
);
}
}
//exports it for use in other files
export default Menu;
-------------------DishdetailComponent.js
//package imports
import React, { Component } from 'react';
//import bootrap components from reactstrap library
//NOTE: The media query returns a CSS style
//creates Dishdetail component
class DishDetail extends Component {
//define a constructor for it
constructor(props) {
//Props is read-only and are used to pass data, whereas state is for managing data and can be modified by its own component
//required when you create a component in react
super(props);
//when document is loaded no card has been selected by default
this.state = {
selectedDish: null,
comments: null
};
}
onDishSelect(comments) {
this.setState({comments: comments});
}
//if dish is clicked it will show card comments, else nothing
renderComments(comments) {
if (comments != null){
return (
<ul key={comments.id} className="list-unstyled">
<li className="comment">{comments.comment}</li>
<li className="author"> {comments.author}</li>
<li className="date"> {comments.date}</li>
</ul>
)
}
else {
return(
<div></div>
)
}
}
//return a value or function that will be called
render() {
//will iterate (map) over the dishes list and return each key (item) uniquely
const details = this.props.comments.map((comments) => {
return (
<div className="container">
<div className="row">
<div className="col-12 col-md-5 m-1">
<h4>Comments</h4>
<div>{comments}</div>
</div>
</div>
</div>
);
});
return (
//This will return a menu list that will be defined
<div className="container">
<div className="row">
{/* This will return the menu items */}
{details}
</div>
<div className="row">
{/* This will return the clicked card dish items when clicked */}
{this.renderComments(this.state.selectedDish)},
</div>
</div>
);
}
}
//exports it for use in other files
export default DishDetail;
----------------------------------------- App.js
//package and component imports
import logo from './logo.svg';
import React, {Component} from 'react';
import { NavbarBrand, Navbar } from 'reactstrap';
import Menu from './components/menuComponent';
import DishDetail from './components/DishdetailComponent';
import './App.css';
import {DISHES} from './shared/dishes';
//creates Menu component
class App extends Component {
//define a constructor for it
constructor (props) {
//Props is read-only and are used to pass data, whereas state is for managing data and can be modified by its own component
//required when you create a component in react
super(props);
//when document is loaded no card has been selected by default
this.state = {
dishes: DISHES,
selectedDish: null,
comments: null
};
}
//when dishg is clicked, it will render details of dish
onDishSelect(dish) {
this.setState({ selectedDish: dish});
}
render () {
return (
//To create html structures in React we always define it via the className strucutre
<div>
{/* This will create a layour based on our individual component files. For example, if we have a navbarComponent file, then we just import it from there and insert it here, without having to code the whole thing. */}
<Navbar color="primary" dark expand="md">
<div className="container">
<NavbarBrand href="/"> Ristorante Con Fusion</NavbarBrand>
</div>
</Navbar>
{/* The Menu component from the menuComponent.js file is rendered here and displayed when the index.js is loaded */}
<Menu dishes={this.state.dishes} />
</div>
);
}
}
//exports it for use in other files
export default App;
I was able to solve it by myself after reading some documentation. It turns out I had to remove the renderDish(dish) function from the menuComponent.js file and place it in the DishdetailComponent.js file.
To solve the
TypeError: Cannot read property 'map' of undefined problem
I did the following:
//if dish is clicked it will show dish comments, else nothing
renderComments(array) {
//if dish array is not equal to null, display comments in half grid
if (array.length != 0) {
return (
//col-12 for sm and xs, and col-5 for md and lg screens with margin @ 1
<div className="col-12 col-md-5 m-1">
{/* Displays the comment title, and details of author, date and comment */}
<h4>Comments</h4>
{/* //will iterate (map) over the comments list and return each key (item) uniquely */}
{ array.map (comment => (
<ul className="list-unstyled">
<li>
<p>{comment.comment}</p>
<p><i> - {comment.author} </i>, {comment.date}</p>
</li>
</ul>
))
}
</div>
);
}
//if the dish contains nothing, show nothing
else {
return (
<div></div>
);
}
}