类型错误:无法读取未定义属性(读取'map')

84

当我尝试运行此代码时,会出现以下错误:

× TypeError:无法读取未定义的属性('map'读取)

为什么会出现这种情况?如何让它正常工作?

import React from 'react';
import Grid from '@material-ui/core/Grid';

import Product from './Product/Product';
import useStyles from './styles';

const products = [
  {id: 1, name: 'Shoes', description: 'Running Shoes.' },
  {id: 2, name: 'MacBook', description: 'Apple MacBook.' },
];

const Products = ({ products }) => {
  const classes = useStyles();

  return (
    <main className={classes.content}>
      <div className={classes.toolbar} />
      <Grid container justify="center" spacing={4}>
        {products.map((products) => (
          <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
            <Product />
          </Grid>
        ))};
      </Grid>
    </main>
  );
};

export default Products;

39
第一次在SO上看到这个错误的新措辞^^ 仍然感觉不真实,因为由于我向v8提出的一个错误,这个超常见的错误消息被更改了。对于不知道的人来说:它的意思与“无法读取未定义的'map'属性”完全相同。 - CherryDT
3
消息更改将掩盖多年的错误消息搜索结果。@CherryDT 你最初发现的那个漏洞很有趣。 - Adam Thompson
1
@CherryDT 原始的错误是什么?有 GH 问题的链接吗?我很想看看这个更改的历史记录。 - no_stack_dub_sack
2
@no_stack_dub_sack https://bugs.chromium.org/p/v8/issues/detail?id=11365 - CherryDT
24个回答

136

我遇到了同样的错误,并通过首先询问数组是否存在来解决它。

例如:

<Filter>
  { product.color?.map((c) => (
    <FilterColor color = {c} key = {c} />
  ))};
</Filter>

9
好的,但为什么这样做有效呢? - Trees4theForest
2
或者它是如何工作的? - B-Tron of the Autobots
1
product.color? 检查 product.color 是否存在,只有在存在时才映射到数组上。 - Claim
1
@Trees4theForest 这是一个被称为“安全导航运算符”的知名技术,它确保我们不会得到空值或未定义的值,并且可以用于防止在尝试访问不存在的对象属性时抛出错误。 维基百科 - Daria Shvydka
除此之外,它还会起作用 { product.color && product.color.map((c) => ( <FilterColor color = {c} key = {c} /> ))}; - Shiplu

15
在你的组件中有一个名为“products”的属性。该变量比你在外面定义的地图具有更高的优先级,而你的.map正在使用它。我建议重命名其中一个,以避免变量名称相同。
鉴于错误,我猜测该属性未传递给组件。
此外,映射lambda的参数也是“products”。请将其更改为“product”,否则它将失败。

2
您可以在以下复制中清楚地看到这些问题:https://codesandbox.io/s/typeerror-cannot-read-properties-of-undefined-reading-map-00jv1?file=/src/App.js - Moshe Jonathan Gordon Radian

9

你得到了一个空数组[]。因此,你遇到了这个错误。你可以通过以下两种方式解决这个问题:

{products && products.map((product) => (
    <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
        <Product/>
    </Grid>
))};

或者

{products?.map((product) => (
    <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
        <Product/>
    </Grid>
))};

7
您传递给组件(Products)的属性 products 是未定义的。 Map 方法正在考虑您传递的 products 属性不是在组件外部创建的那个属性。
如果您想映射出在组件外部创建的 products 数组,则只需更改其名称,因为该数组与传递的属性具有相同的名称。 如果要使用属性中的 products,请确保将属性传递给组件。

6
这是因为您将数组"products"和映射项"products"命名为相同的名称。请将映射项更改为其他名称,例如"product"。
const products = [
        {id: 1, name: 'Shoes', description: 'Running Shoes.' },
        {id: 2, name: 'MacBook', description: 'Apple MacBook.' },
    ];

const Products = ({ products }) => {
  const classes = useStyles();

  return (
    <main className={classes.content}>
      <div className={classes.toolbar} />
      <Grid container justify="center" spacing={4}>
        {products.map((product) => (
          <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
            <Product/>
          </Grid>
        ))};
      </Grid>
    </main>
  );
};

5

使用:

const Products = ({ products }) => {
  const classes = useStyles();

  return (
    <main className={classes.content}>
      <div className={classes.toolbar} />
      <Grid container justify="center" spacing={4}>
        {products && products.map((products) => (
          <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
            <Product />
          </Grid>
        ))};
      </Grid>
    </main>
  );
};

只需添加 "products &&",这将检查地图是否已定义。

3
这样写问题就会得到解决:
<Grid container justify="center" spacing={4}>
  {products ?.map((product) => (
    <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
      <Product/>
    </Grid>
  ))};
</Grid>

2
步骤1:在用户页面中添加加载 - 使用useState
{const [loading, setLoading] = useState(true);}

步骤2:在异步获取函数的结尾将加载值设置为false。 如果您使用try-catch方法,则将此代码行放置在try方法内:

  {   setLoading(false)}

步骤三:在代码的render()部分内使用一元操作符。
{ loading ? (
  <h2>loading</h2>
) :  {/* Enter code here */}}

2
请确保将产品属性传递到Product组件中。更改为:
{products.map((products) => (
              <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
                <Product/>

转换为:

{products.map((products) => (
              <Grid item key={products.id} item xs={12} sm={6} md={4} lg={3}>
                <Product/>

为什么?因为在你的情况下,你正在将一个对象(products)映射到JSX元素中,即<Product/>组件,所以使用{ product.id }会尝试映射未定义的对象。 然后请确保你尝试映射的products属性已正确传递到父组件中,使用Products组件。

2

使用:

 { product.color?.map((c) => (
    <FilterColor color = {c} key = {c} />
  ))};

这将解决问题,但为什么它会在幕后出现?React 不会立即更新状态。这个概念被称为调度,这就是为什么当你访问 products.map 时,products 是一个空数组的原因。

1
这个回答有意义吗? - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接