开发者问题收集

如何解决 TypeError:无法读取未定义的属性“map”?

2020-04-15
667

我一直收到此错误

TypeError: Cannot read property 'map' of undefined`

DISHES 对象从 dishes.js 导入并加载到 App.js 组件中的状态对象 dishes 中,然后在 App.js 中呈现时,它通过 Menu 组件作为 props 传递给 MenuComponent.js

我不知道为什么,一切似乎都正确,这是一项在线课程的作业,我已经看到其他参加该课程的人所做的更正,他们似乎在做与我完全一样的事情,并且对他们有效。

输出

在此处输入图像描述

App.js

import React, {Component} from 'react';
import {Navbar, NavbarBrand} from 'reactstrap';
import './App.css';
import Menu from './components/MenuComponent';
import { DISHES } from "./shared/dishes";


class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      dishes: DISHES
    };
  }
  render() {
    return (
      <div>
        <Navbar dark color="primary">
          <div className="container">
            <NavbarBrand href="/">Ristorante Con Fusion</NavbarBrand>
          </div>
        </Navbar>
        <Menu dishes={this.state.dishes}/>
      </div>
    );
  }
}

export default App;

MenuComponent.js

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

class Menu extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedDish: null
    };
  }

  onDishSelect(dish) {
    this.setState({selectedDish: dish});
  }

  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>
      );
    }
  }

  render() {
    const menu = this.props.dishes.map((dish) => {
      return (
        <div key={dish.id} className="col-12 col-md-5 m-1">
          <Card onClick={() => this.onDishSelect(dish)}>
            <CardImg width="100%" src={dish.image} alt={dish.name}/>
            <CardImgOverlay>
              <CardTitle>{dish.name}</CardTitle>
            </CardImgOverlay>
          </Card>
        </div>
      );
    });

    return (
      <div className="container">
        <div className="row">
          {menu}
        </div>
        <div className="row">
          {this.renderDish(this.state.selectedDish)}
        </div>
      </div>
    );
  }
}

export default Menu;

dishes.js

export const DISHES =
[
    {
    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"
        }
    ]
    }
];
3个回答

您有此组件 <Menu dishes={this.state.dishes}/> ,它需要一个 dishes prop。

现在在 <App> 中,您调用 this.setState() ,但它是异步的,并且在第一次渲染 <App> (以及 <Menu> )时, this.state.dishes 的值仍然为 undefined ,因此 <Menu> 中的 this.props 也是 undefined

当它确实更新时,会重新渲染,并且 <App><Menu> 会使用正确的方式渲染值。

因此,您可以添加对 undefined 的检查,以便 .map() 仅在 this.props 具有值时运行。

这就是 this.props && this.props.dishes.map() 所做的。本质上,它意味着 if(this.props){ this.props.dishes.map() ,因此当 this.propsundefined 时,不会执行第二个表达式。

setState 完成后, this.props 被定义,并且您将获得结果。

Anurag Srivastava
2020-04-15

为了避免任何 props 未定义值,您可以使用库 prop-types ,在其中定义您的 props 默认值,这样如果 props 值未传输到您的组件,您的组件仍将具有默认值以按预期运行。例如,在您的 props 从一开始就没有定义的情况下(这可能是这里的情况),它很有用。

为此,请安装库:

npm install --save prop-types

然后在您的 MenuComponent 文件中,在文件顶部添加导入:

import PropTypes from 'prop-types';

最后,在文件末尾,添加此 props 类型检查和默认值:

// Define the props types to check
Menu.propTypes = {
  dishes: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.number,
    name: PropTypes.string,
    image: PropTypes.string,
    category: PropTypes.string,
    label: PropTypes.string,
    price: PropTypes.string,
    description: PropTypes.string,
    comment: PropTypes.arrayOf(PropTypes.shape({
      id: PropTypes.number,
      rating: PropTypes.number,
      comment: PropTypes.string,
      author: PropTypes.string,
      date: PropTypes.string,
    })),
  })),
};

// Define here the default value to attribute to your dishes props
Menu.defaultProps = {
  dishes: [],
};

export default Menu;

希望这对您有帮助!

Orlyyn
2020-04-15

我正在上同一门课,我复制并粘贴了你的代码,没有任何问题。请确保你的 index.js 文件也像这样。如果这不是问题,那么你的导入可能已正确安装。由于 MenuComponent 存在问题,因此可能 React 未正确下载。

不确定问题是什么,但我不认为这是代码的问题。

import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();
pchung24
2020-10-28