Trouble mapping over an array of images in a Next.js starter

3 replies
Last updated: Jun 2, 2020
Mapping Over Array of Image - Hey peeps, I'm using the nextjs starter and I've got a few components I will need to build that must accept multiple image files, for example, grids, image sliders, two column layouts. I'm also trying to adapt the Hero component to accept multiple images that I can cycle through. I've changed the schema to accept an array rather than an object. However I'm having trouble getting this to translate on the front end....


function Hero(props) {
  const { heading, backgroundImage, tagline, ctas, node } = props;

  console.log(backgroundImage);

  return (
    <div className={styles.root}>
      <div className={styles.content}>
        <h1 className={styles.title}>{heading}</h1>
        {backgroundImage.map((background) => (
          <>
            <img src={`${urlFor(backgroundImage).width(2000).auto("format").url()}`} />
          </>
        ))}
        <div className={styles.tagline}>{tagline && <SimpleBlockContent blocks={tagline} />}</div>
        {ctas && (
          <div className={styles.ctas}>
            {ctas.map((cta) => (
              <Cta {...cta} key={cta._key} />
            ))}
          </div>
        )}
      </div>
    </div>
  );
}
AI Update

I can see the issue in your code! You're mapping over backgroundImage array but then still using the entire backgroundImage array inside urlFor() instead of using the individual background item from the map. Here's the fix:

function Hero(props) {
  const { heading, backgroundImage, tagline, ctas, node } = props;

  console.log(backgroundImage);

  return (
    <div className={styles.root}>
      <div className={styles.content}>
        <h1 className={styles.title}>{heading}</h1>
        {backgroundImage.map((background) => (
          <img 
            key={background._key} 
            src={urlFor(background).width(2000).auto("format").url()} 
          />
        ))}
        <div className={styles.tagline}>{tagline && <SimpleBlockContent blocks={tagline} />}</div>
        {ctas && (
          <div className={styles.ctas}>
            {ctas.map((cta) => (
              <Cta {...cta} key={cta._key} />
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

Key changes:

  1. Use background instead of backgroundImage inside the map function - you want to process each individual image, not the whole array
  2. Add a key prop - React needs unique keys for mapped elements. Since you're mapping over an array field in Sanity, each item should have a _key property
  3. Remove the empty fragment (<></>) - it's unnecessary when you're only returning a single element

For your schema, make sure it looks something like this:

{
  name: 'backgroundImage',
  title: 'Background Images',
  type: 'array',
  of: [
    {
      type: 'image',
      options: {
        hotspot: true
      }
    }
  ]
}

This pattern will work for all your other components that need multiple images (grids, sliders, two-column layouts). Just remember: when you map over the array, use the iterator variable (like background) inside the map function, not the original array variable.

If you want to add alt text or other metadata to your images, you can enhance the schema with custom fields as described in the Sanity image type documentation:

{
  name: 'backgroundImage',
  title: 'Background Images',
  type: 'array',
  of: [
    {
      type: 'image',
      options: {
        hotspot: true
      },
      fields: [
        {
          name: 'alt',
          title: 'Alt Text',
          type: 'string'
        }
      ]
    }
  ]
}

Then access it in your component: background.alt

1. This is my console output
(2) [{…}, {…}]
2.
0: {_key: "b4579d75774a", _type: "image", asset: {…}}
3.
1: {_key: "e93fe9ec7b24", _type: "image", asset: {…}}
4.
length: 2
5.
__proto__: Array(0)

Hi User, inside the
backgroundImage
array that you map, have you tried replacing:
{`${urlFor(backgroundImage).width(2000).auto("format").url()}`}
… with this?

{`${urlFor(background).width(2000).auto("format").url()}`}
This should let
urlFor
use an array item instead of the entire array, which hopefully resolves the issue.
Great that worked thanks User, I've actually decided to use it as img rather than a background image but same principles, I was just passing the data in incorrectly!

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?