admin管理员组

文章数量:1394611

I'm trying to make a emerce site using the merce.js library. I have already 8 products in the library API. I have a Products.js ponent where I'm passing those array of product objects I got from App.js and again passing single product object to the Product.js ponent. To do this, I'm using mapping function to pass each object as props to the Product.js ponent. And I'm receiving this error. I tried menting out the mapping block and only console logged the products variable from App.js and the prop products in Products.js, there I'm getting all the 8 products so no problem in there. But I don't get it why I'm getting this error in the mapping function.

App.js

import React, { useState, useEffect } from "react";
import { merce } from "./lib/merce";
import { Products, Navbar } from "./ponents";

function App() {
  const [products, setProducts] = useState([]);

  const fetchProduct = async () => {
    const data = await merce.products.list();
    setProducts(data);
  };
  useEffect(() => {
    fetchProduct();
  }, []);

  console.log("products", products);

  return (
    <div className="App">
      <Navbar />
      <Products products={products} />
    </div>
  );
}

export default App;

Products.js

import React from "react";
import { Grid } from "@material-ui/core";
import Product from "./Product/Product";
import useStyles from "./style";

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

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

export default Products;

Product.js

import React from "react";
import {
  Card,
  CardMedia,
  CardContent,
  CardActions,
  Typography,
  IconButton,
} from "@material-ui/core";
import { AddShoppingCart } from "@material-ui/icons";
import useStyles from "./styles";

const Product = ({ product }) => {
  const classes = useStyles();
  return (
    <Card className={classes.root}>
      <CardMedia
        className={classes.media}
        image={product.media.source}
        title={product.name}
      />
      <CardContent>
        <div className={classes.cardContent}>
          <Typography variant="h5" gutterBottom>
            {product.name}
          </Typography>
          <Typography variant="h5">
            {product.price.formatted_with_symbol}
          </Typography>
        </div>
        <Typography
          variant="body2"
          dangerouslySetInnerHTML={{ __html: product.description }}
        />
      </CardContent>
      <CardActions disableSpacing className={classes.cardActions}>
        <IconButton aria-label="Add to Cart">
          <AddShoppingCart />
        </IconButton>
      </CardActions>
    </Card>
  );
};

export default Product;

I'm trying to make a emerce site using the merce.js library. I have already 8 products in the library API. I have a Products.js ponent where I'm passing those array of product objects I got from App.js and again passing single product object to the Product.js ponent. To do this, I'm using mapping function to pass each object as props to the Product.js ponent. And I'm receiving this error. I tried menting out the mapping block and only console logged the products variable from App.js and the prop products in Products.js, there I'm getting all the 8 products so no problem in there. But I don't get it why I'm getting this error in the mapping function.

App.js

import React, { useState, useEffect } from "react";
import { merce } from "./lib/merce";
import { Products, Navbar } from "./ponents";

function App() {
  const [products, setProducts] = useState([]);

  const fetchProduct = async () => {
    const data = await merce.products.list();
    setProducts(data);
  };
  useEffect(() => {
    fetchProduct();
  }, []);

  console.log("products", products);

  return (
    <div className="App">
      <Navbar />
      <Products products={products} />
    </div>
  );
}

export default App;

Products.js

import React from "react";
import { Grid } from "@material-ui/core";
import Product from "./Product/Product";
import useStyles from "./style";

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

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

export default Products;

Product.js

import React from "react";
import {
  Card,
  CardMedia,
  CardContent,
  CardActions,
  Typography,
  IconButton,
} from "@material-ui/core";
import { AddShoppingCart } from "@material-ui/icons";
import useStyles from "./styles";

const Product = ({ product }) => {
  const classes = useStyles();
  return (
    <Card className={classes.root}>
      <CardMedia
        className={classes.media}
        image={product.media.source}
        title={product.name}
      />
      <CardContent>
        <div className={classes.cardContent}>
          <Typography variant="h5" gutterBottom>
            {product.name}
          </Typography>
          <Typography variant="h5">
            {product.price.formatted_with_symbol}
          </Typography>
        </div>
        <Typography
          variant="body2"
          dangerouslySetInnerHTML={{ __html: product.description }}
        />
      </CardContent>
      <CardActions disableSpacing className={classes.cardActions}>
        <IconButton aria-label="Add to Cart">
          <AddShoppingCart />
        </IconButton>
      </CardActions>
    </Card>
  );
};

export default Product;
Share Improve this question asked Sep 25, 2021 at 18:22 buzzbuzz 1,1264 gold badges13 silver badges26 bronze badges 4
  • 1 const [products, setProducts] = useState([]); products starts off as an array, and arrays don't have a .data property on them. Did you mean to do a different initial value? Or perhaps did you mean to do products.map instead of products.data.map? – Nicholas Tower Commented Sep 25, 2021 at 18:24
  • No when I got the data from the API it had like this products { data: [Array of my products], metadata: {...} So to map I had to go through the chaining process – buzz Commented Sep 25, 2021 at 18:26
  • 1 Ok, then change your initial state so it has the same shape. It needs to be an object with a data property that is an array. ie, useState({ data: [] }) – Nicholas Tower Commented Sep 25, 2021 at 18:27
  • could you please explain why I had to set like this, It is working this way but when I'm setting the API response in array eventually through chaining I'm accessing the data. But why I had to explicitly set the initial value to {data:[]} – buzz Commented Sep 25, 2021 at 18:32
Add a ment  | 

2 Answers 2

Reset to default 4

In your App.js change your fetchProduct function as follows:

const fetchProduct = async = {
    const products = await merce.products.list();
    setProducts(products.data);
}

and then in your Products.js map over the products instead of products.data,

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

EXPLANATION:
The initial State of products is an empty array, which is passed down to the products ponent, where you tried products.data.map() but products is an array (initially) and there is no data property on arrays, so it threw error.
There are several ways you can get around this, but if you are only using the products data from the response then you can go with the above approach, where you map over the products not products.data and setProducts() with the products array instead of products object.

Do you can to attached screen with error?

I think, you try to read data before is are loading, you can prevent this by add something like this (products.data || []).map for example.. or change default state in App.js on useState({data:[]})

本文标签: javascriptCannot read properties of undefined (reading 39map39) in ReactStack Overflow