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

时间:2020-04-15 08:24:49

标签: javascript reactjs react-props

我一直遇到这个错误

TypeError:无法读取未定义的属性“ map”

dishes.js 导入

DISHES对象,并将其加载到 App.js 组件的状态对象盘中,然后将其作为道具传递给<通过 App.js

中呈现的菜单组件来实现strong> MenuComponent.js

我不知道为什么,一切似乎都正确,这是一项在线课程的一部分,我已经看过其他参加过该课程的人所做的更正,他们似乎在做与我,对他们有用。

输出

enter image description here

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 个答案:

答案 0 :(得分:2)

您拥有此组件<Menu dishes={this.state.dishes}/>,该组件需要dishes道具。

现在在<App>中,您调用this.setState(),但它是异步的,并且在<App>(因此也是<Menu>)的第一个呈现上,值{{1 }}仍为this.state.dishes,因此undefined中的this.props也是<Menu>

当它确实更新时,将进行重新渲染,并且undefined<App>将使用正确的值进行渲染。

因此,您可以添加对<Menu>的检查,以使undefined仅在.map()有值时运行。

this.props就是这样做的。从本质上讲,它的意思是this.props && this.props.dishes.map(),因此,当if(this.props){ this.props.dishes.map() }this.props时,将不执行第二个表达式。

完成undefined之后,定义setState,就可以得到结果。

答案 1 :(得分:1)

为避免任何道具未定义值,您可以使用库prop-types,在其中定义道具默认值,这样,如果道具值未传输到组件,则组件仍将具有默认值表现出预期。例如,在不从一开始就定义道具的情况下,这很有用。

为此,请安装库:

npm install --save prop-types

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

import PropTypes from 'prop-types';

最后,在文件末尾,添加以下道具类型检查和默认值:

// 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;

希望这会有所帮助!

答案 2 :(得分:0)

我要上同一堂课,所以我没有问题地复制并粘贴了您的代码。确保index.js文件也是如此。如果这不是问题,则可能是您的导入已正确安装。由于MenuComponent存在问题,可能是反应未正确下载。

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

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