Issue with mapping array of images in React component

3 replies
Last updated: May 28, 2023
Hi, i have a question. I am trying to map an array of images but it displays null in the console. What could be the issue?here is the code: import React, {useState, useEffect} from 'react'
import {client} from '../../lib/client'
import { urlFor } from '../../lib/client'
import {FaCrown} from 'react-icons/fa'
import {AiOutlineShoppingCart} from 'react-icons/ai'
import { Link } from 'react-router-dom'
import Sectionhead from '../Sectionhead/Sectionhead'
import { Button, Card, CardActionArea, CardActions, CardContent, CardMedia, Grid} from '@mui/material'
import './product.css'





const Products = () => {
const [product, setProduct] = useState([])

useEffect(() =>{
client.fetch(

*[_type == "product"] {
            name, images[]{
    "imageUrl": asset->url
  }, slug, price
          }
).then((data) => setProduct(data)).catch(console.error)
}, [])
console.log(product)

return (
<>
<section className='products'>
<Sectionhead icon={<FaCrown/>} title='Products' className='head'/>
<Grid container justify='center' spacing={1}>
{
product.map((product) => (
<Grid item key={product.slug.current} xs={12} sm={6} md={4} lg={3}>
<Card sx={{flexGrow: 1}} className='custom-card'>
<CardActionArea>
<CardMedia component="img" title={product.name} height='200' className="card-image"/>
<CardContent className='content'>
<h3>{product.name}</h3>
</CardContent>
</CardActionArea>
<CardActions className='h4'>
<h4>Ksh.{product.price}</h4>
</CardActions>

<CardActions className='actions-content'>
<Button
size="large"
className="batoni"
sx={{fontFamily:'Sono'}}
>
<Link to={
/product/${product.slug.current}
}><AiOutlineShoppingCart /> SHOP</Link> </Button>
</CardActions>
</Card>
</Grid>
))
}
</Grid>
</section>
</>
)
}

export default Products
AI Update

I can see the issue in your code! The problem is that you're not actually passing the image URL to your CardMedia component.

In your JSX, the CardMedia component is missing the image prop:

<CardMedia component="img" title={product.name} height='200' className="card-image"/>

The fix: You need to add the image source. Since images is an array, you'll want to access the first image:

<CardMedia 
  component="img" 
  image={product.images[0]?.imageUrl} 
  title={product.name} 
  height='200' 
  className="card-image"
/>

The ?. (optional chaining) prevents errors if the images array is empty or undefined.

Alternative approach using your urlFor helper:

Since you've already imported urlFor, you could also modify your query to return the full asset reference instead of just the URL:

*[_type == "product"] {
  name, 
  images,
  slug, 
  price
}

Then use urlFor in your component:

<CardMedia 
  component="img" 
  image={product.images[0] ? urlFor(product.images[0]).url() : ''} 
  title={product.name} 
  height='200' 
  className="card-image"
/>

The first approach (with asset->url in your query) is simpler and should work fine for your use case. The urlFor approach from @sanity/image-url is more powerful when you need to apply transformations like resizing, cropping, or format conversion (e.g., .width(400).format('webp')).

Either way, the key issue is that you're fetching the images correctly but not actually passing them to the CardMedia component's image prop!

Hi, here is the method how I used to get my images array:
groq`*[_type == 'page' &amp;&amp; slug.current == $slug][0]{
_id,
_createdAt,
"images": images[].asset-&gt;url,
title,
"slug": slug.current,
content,
}`,
not yet my console is still displaying null here is the schema: exportdefault {    name: 'product',
    title: 'Product',
    type:'document',
    fields: [
        {
            name: 'image',
            title: 'Image',
            type: 'array',
            of: [{type: 'image'}],
            options: {
                hotspot: true,
            }
        },
        {
            name:'name',
            title:'Name',
            type:'string',
        },
        {
            name:'slug',
            title:'Slug',
            type:'slug',
            options: {
                source:'name',
                maxLength:90,
            }
        },
        {
            name:'price',
            title:'Price',
            type:'number',
        },
        {
            name:'details',
            title:'Details',
            type:'string',
        }
    ]
}
Your name on schema written as "image", however in your query you name it as "images". So both of these names have to be same

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?