Reputation: 96
When I make API call and store the response in useState, it shows the data while running console.log(), however when this state value is passed as an argument to another component which is supposed to take the data and mapped it to show the result, it gives me an error saying " Cannot read properties of undefined (reading 'map')" Can anyone help me figure out what's wrong with my code?
Edit - As Mr.Silva suggested below, I added {menFootwears && menFootwears.map((menFootwear)=> () )}
It no longer shows error anymore, however, it also doesn't show the data even though the data shows as an output in console.log() in Product.jsx whereas it shows undefined in MenShoes.jsx and WomenShoes.jsx
Here's my code for Product.jsx
import { useMediaQuery } from '@mui/material';
import { Box } from '@mui/system';
import React from 'react'
import { theme } from '../style/theme';
import MenShoes from './collections/MenShoes';
import WomenShoes from './collections/WomenShoes';
export const Products = () => {
const matchScreen = useMediaQuery(theme.breakpoints.down('md'))
const [isLoading, setIsLoading] = React.useState(true);
const [menFootwears, setMenFootwears] = React.useState([]);
const [womenFootwears, setWomenFootwears] = React.useState([]);
//Women FootWears
async function fetchWomenFootwear () {
setIsLoading(true)
await fetch('https://dummyjson.com/products/category/womens-shoes')
.then(response => response.json())
.then(response => setWomenFootwears(response.products))
setIsLoading(false);
}
//Men Footwears
async function fetchMenFootwear () {
setIsLoading(true)
await fetch('https://dummyjson.com/products/category/mens-shoes')
.then(response => response.json())
.then(response => setMenFootwears(response.products))
setIsLoading(false)
}
React.useEffect(()=> {
fetchWomenFootwear()
fetchMenFootwear()
}, [])
const handleProductCard = (id) => {
console.log('hello')
}
console.log( womenFootwears, menFootwears)
return (
<Box>
<WomenShoes data={womenFootwears} onclick={handleProductCard} loadingStatus={isLoading}/>
<MenShoes data={menFootwears} onclick={handleProductCard} loadingStatus={isLoading}/>
</Box>
)
}
Both WomenShoes and MenShoes are designed using the same code except for the API response array data.
MenShoes/WomenShoes.jsx
import { ShoppingCartSharp } from '@mui/icons-material';
import { Button, Card, CardActionArea, CardContent, CardMedia, Divider, Rating, Skeleton, Typography, useMediaQuery } from '@mui/material';
import { Box } from '@mui/system';
import React from 'react'
import { theme } from '../../style/theme';
export default function MenShoes({menFootwears, handleProductCard, isLoading}) {
const matchScreen = useMediaQuery(theme.breakpoints.down('md'))
return(
<Box pt={2} mt={4}>
<Divider variant='middle' sx={{
"&.MuiDivider-root": {
"&::before, &::after": {
borderTopColor:theme.palette.primary.light,
borderTopWidth:'thin',
borderTopStyle:'solid'
},
}
}}>
<Typography color={theme.palette.primary.main} variant={!matchScreen ? 'h3': 'h5'}>
Men Footwears Collections
</Typography>
</Divider>
<Box display='flex'
justifyContent='space-evenly'
alignItems='center'
flexWrap='wrap'
pt={2}
mt={2}
px={2}>
{menFootwears.map((menFootwear)=> (
<Card key={menFootwear.id}
sx={{maxWidth:335,
height:'auto',
marginTop:'3.5em',
flex:!matchScreen ? '0 0 45%' : '0 0 80%'
}}
elevation={4}
onClick={()=>{handleProductCard(menFootwear.id)}}>
<CardActionArea>
{isLoading ?
<>
<Skeleton variant='rectangular' width='335' height='220' animation='wave'/>
</> :
<CardMedia component='img'
height='220'
image={menFootwear.images[0]}/>}
<CardContent sx={{
textAlign:'center',
}}>
{ isLoading ?
<>
<Skeleton variant='h6' animation='wave'/>
</> :
<Typography gutterBottom variant='h6'
fontWeight='bold'
color={theme.palette.primary.main}>
{menFootwear.title}
</Typography>}
{isLoading ?
<>
<Skeleton variant='body2' animation='wave'/>
</> :
<Typography variant='body2' gutterBottom color={theme.palette.primary.dark}>
Brand : {menFootwear.brand}
</Typography>}
{ isLoading ?
<>
<Skeleton variant='h5' animation='wave'/>
</> :
<Typography variant='h5' gutterBottom color={theme.palette.primary.main}>
$ {menFootwear.price}
</Typography>}
<Rating
size='small'
name="rating"
value={menFootwear.rating}
readOnly/>
</CardContent>
</CardActionArea>
{ isLoading ?
<>
<Skeleton variant='rectangular' width='335' height='20' animation='wave'/>
</> :
<Button size='medium'
sx={{all:'unset',
textAlign:'center',
fontFamily:theme.typography.fontFamily,
fontSize:16,
width:'100%',
padding:'0.7em',
margin:0,
color:'white',
background:`linear-gradient(90deg, ${theme.palette.primary.main},transparent) ${theme.palette.tertiary.main}`,
transition:'background 0.5s',
'&:hover': {
background:theme.palette.secondary.main,
}
}}>
<span style={{display:'inline-flex', alignItems:'center'}}>
<ShoppingCartSharp size='small'/> Add to Cart
</span>
</Button>}
</Card>
))}
</Box>
</Box>
)
}
Upvotes: 0
Views: 418
Reputation: 11
Check before using the map if the variable menFootwears is not undefined or if the array is empty.
{menFootwears && menFootwears.map(el => () )}
Upvotes: 1