79

When I try to run this code it gives me this error:

× TypeError: Cannot read properties of undefined (reading 'map')

Why does it happen? How can I make it work?

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;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
udenyi
  • 791
  • 1
  • 4
  • 3
  • 37
    First time I see this error in its new wording on SO ^^ still feels unreal that this super-common error message was changed due to a bug I opened with v8. For people unaware of it: it means exactly the same as `Cannot read property 'map' of undefined` did. – CherryDT Sep 06 '21 at 22:02
  • 2
    The message change will obscure many years of error message search results. @CherryDT Interesting bug you found originally though. – Adam Thompson Oct 19 '21 at 23:02
  • 1
    @CherryDT what was the original bug? Have a link to the GH issue? I would be interested to see the history of this change – no_stack_dub_sack Nov 12 '21 at 01:44
  • 2
    @no_stack_dub_sack https://bugs.chromium.org/p/v8/issues/detail?id=11365 – CherryDT Nov 12 '21 at 08:54

23 Answers23

129

I had the same error and solved it by first asking if the array existed.

Example:

<Filter>
  { product.color?.map((c) => (
    <FilterColor color = {c} key = {c} />
  ))};
</Filter>
jake
  • 1,391
  • 1
  • 8
  • 2
  • 7
    Yes... but why does this work? – Trees4theForest Oct 30 '22 at 05:42
  • 1
    `product.color?` checks if `product.color` exists and maps only then over the array. – Claim Mar 21 '23 at 12:12
  • 1
    @Trees4theForest it’s a known “Safe Navigation Operator”, which makes sure that we will not get null and/or undefined values, can be used to prevent from throwing errors, when trying to access object properties of an object that don’t exist. [wiki](https://en.wikipedia.org/wiki/Safe_navigation_operator) – Daria Shvydka Aug 16 '23 at 10:41
  • Insteed of this, it will also work { product.color && product.color.map((c) => ( ))}; – Shiplu Aug 22 '23 at 07:09
15

There is a property "products" in your component. That variable has higher priority than the map you have outside, and your .map is using it. I would recommend to rename one of them, to avoid variables with the same name.

Given the error, I would guess that that property wasn't passed to the component.

Also, the parameter of the map lambda is "products" too. Change it to "product", or it will fail.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Iván
  • 971
  • 6
  • 20
9

You are getting a blank array[]. For this, you are facing this error. You can solve this problem two ways:

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

Or

{products?.map((product) => (
    <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
        <Product/>
    </Grid>
))};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Md. Shafiqul Islam
  • 196
  • 1
  • 4
  • 9
7

The properties, products, that you're passing to your component (Products) are undefined. The Map method is taking in account the products that you have passed as properties is not the one that you have created outside the component itself.

If you want to map out the products array that you created outside of your components then just change its name as the array has the same name as the properties passed. If you want to use the products (from the property) then make sure that you're passing the properties in the component.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abdullah Ch
  • 1,678
  • 1
  • 13
  • 31
6

It's because you have taken the array "products" and the map item "products" by the same name. Change the map item to something else like "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>
  );
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dawood Ahmad
  • 476
  • 4
  • 13
5

Use:

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

Just add "products &&". This will check if the map is defined or not.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
vishal
  • 61
  • 1
  • 1
3

Write it in this way and the issue would be resolved:

<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>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

Make sure to pass the products properties into the Product component. Change this:

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

to this:

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

Why? Because you're mapping an object (products) into a JSX element in your case which is the <Product/> component, so using { product.id } you're trying map an undefined object. Then make sure the products property you're trying to map out, is correctly passed into the parent component using the Products component.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Primrose
  • 23
  • 2
2

Step 1: Add loading into user page - use useState

{const [loading, setLoading] = useState(true);}

Step 2: Set loading value to false at the end of async fetch function. If you’re using the try-catch method, put this code line inside the try method:

  {   setLoading(false)}

Step 3: Use a unary operation in the inside the render() part of the code

{ loading ? (
  <h2>loading</h2>
) :  {/* Enter code here */}}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sai nath
  • 31
  • 2
2

Use:

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

This would fix the issue, but why does it appear well behind the scene? React won't update the state immediately. This concept is called scheduling, and that is why when you access products.map, products are an empty array.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

At first, please check that products are exported. If yes, then change

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

to

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

Because here you map products as products, so you have to set the key like products.id.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • Perhaps mark the literal parts with italics (so it is clear what is and what isn't literal)? (But ***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today.) – Peter Mortensen Aug 15 '22 at 19:58
1

You had named each iteration of the map method with products, but you are using product to catch each instance of the iteration.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mushahid
  • 11
  • 2
1

You should basically check the values received are undefined or not.

In Angular, you can use something like this: {{person?.name}}.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sagar M
  • 1,168
  • 13
  • 10
1

You can replace the map part like this:

{(products|| []).map(product) => ( // Your code ))}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 06 '22 at 02:25
  • That's Brillant, I was having similar issue and your solution works for me :) – Karim Elnemr Jul 01 '22 at 16:09
1

Use:

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

Here changes in products && products.map() instead of products.map().

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

Make sure properties is not undefined.

typeof products.map() !== undefined
JUGG
  • 41
  • 3
1

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

// add "products &&" before the map method
0
        {products && products.map((product) => (
          <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
            <Product />
          </Grid>
        ))};
  • 5
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – Ahmet Emre Kilinc Oct 28 '21 at 17:46
  • I had a similar problem which this approach solved. Although unlike the hard coded `products` array in this question I was fetching an array of data from a database. Anyway, the idea is that `products && products.map(.....` is first checking to make sure that `products` isn't undefined (or has a truthy value at least). If it's undefined, the `products.map` won't execute. – DC1477 Nov 19 '21 at 08:43
0

Sometimes, it gives an error when you haven't used the variable of useState.

And I have made two other components. 1) Tour 2) Tours

 const [tours, setTours ] = useState([]);

Now, I have used this tours variable in App.js file using Tours components.

App.js

I have used tours in the App.js file.

App.js

Now, I'm taking the tours variable for using the .map() function in the Tours.js file.

const Tours = ({ tours }) => {
/...
{tours.map()
.../

Tours.js

You have to check that both files have the same spelling. Otherwise, it gives an error and also doesn’t work the UI of that particular file.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Avi
  • 31
  • 4
0

You should try this:

{products.map((product) => (
  <Grid item key={product.id} item xs={12} sm={6} md={4} lg={3}>
    <Product/>
  </Grid>
))};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

You had this kind of error because you don't pass any information (props) inside the product component. So try this:

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 product={product} />
          </Grid>
        ))};
      </Grid>
    </main>
  );
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0
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>
  );
};
-1

Check INITIAL_STATE in the reducer.

You must specify an array in the ID object you are calling in the reducer.

Example:

const INTIAL_STATE = {
    products: [],
    product: { name: "", brand_name: "", prices: "", color: "", images: []},
    error: "",
}

product.images.map(img => {
    return(
        <div key = {img.id} className = "img-itemm">
            <img src = {img.image} alt = {img.image} />
        </div>
    )
})
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131