为什么我的 React 应用程序会出现此错误?

Why am i getting this error in my React application?

我在编译我的 React 应用程序时遇到此错误:类型错误:无法读取未定义的属性(读取 'comments')。

导致此问题的代码部分是我的 Dishdetailcomponent.js

的第 85 行

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}&nbsp;{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; 

上面的组件是应该在页面末尾显示所选菜肴的演示组件。

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;

上面的组件是将props传递给Dishdetail组件的容器组件

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.

因为selectedDish的初始值为空。所以 filter 将 return 一个空数组。 dish 将是 undefined.

您应该在 return 之前检查 this.props.dish 的值而不是 this.props

if (this.props.dish != 'undefined')
    return (

render() {
    console.log(this.props);
    console.log('Dishdetail component render is invoked');
    if (this.props.dish != 'undefined')
        return (
        <div className="container">
...

并且您应该使用 find 而不是 filter 来查找数组中的元素。

<DishDetail dish={this.state.dishes.find((dish) => dish.id === this.state.selectedDish)} />

您在 Main 中的初始状态是:

this.state = {
  dishes: DISHES,
  selectedDish: null
};

然后将 dishes 状态过滤到一个数组中,并将第 0 个元素传递给 dish 属性上的 DishDetail

<DishDetail
  dish={this.state.dishes.filter((dish) => 
    dish.id === this.state.selectedDish)[0]
  }
/>

在初始渲染周期中,过滤 returns 一个空数组,因为没有 dish 项具有空值 id 属性,因此 dish 属性未定义。

稍后在 DishDetailrenderComments 你试图通过 this.props.dish.comments:

<div  className="col-12 col-md-5 m-1">
  {this.renderComments(this.props.dish.comments)}
</div>

由于 this.props.dish 未定义,您无法进一步访问该对象。

解决方案

无论您传递 dish 属性,您都应该在调用 renderComments.

之前首先检查 this.props.dishthis.props.dish.comments 是否存在
<div  className="col-12 col-md-5 m-1">
  {this.props.dish?.comments && this.renderComments(this.props.dish.comments)}
</div>

<div  className="col-12 col-md-5 m-1">
  {this.props.dish 
    && this.props.dish.comments
    && this.renderComments(this.props.dish.comments)}
</div>