Undefined slug.current and post.image when querying referenced vs referencing images

15 replies
Last updated: May 27, 2021
Kia ora! I have a follow up to a previous query - https://sanity-io-land.slack.com/archives/C9Z7RC3V1/p1619497015485200
I’ve successfully been able to reference the images I’m looking for, but I’m unable to use them in my front end for some reason! The only difference between this page and another is how I’m querying the images - in this gist, [slug].js is querying all image documents that reference this document (camera), and in [slug-1].js I’m querying a list of images that this document (collection) references.

There must be something I’m missing in how I process these queries and join the data, because next is giving me undefined for slug.current and post.image! Can anyone help?


https://gist.github.com/jenkshields/ec7a11fe3b0f830c40276c4343d33620
AI Update

Looking at your gist, I can see the issue! In [slug-1].js (the collection page), you're mapping over post.images but then trying to render post.slug.current and post.image outside the map function. The problem is that post in that context refers to your collection document, not the individual image documents.

Here's what's happening:

In your working [slug].js (camera page):

{post.photos.map((post) => {
  // Here 'post' is each individual photo document
  return (
    <Link href={`/photo/${encodeURIComponent(post.slug.current)}`}>
      <Image src={urlFor(post.image).auto('format').url()} />
    </Link>
  )
})}

In your broken [slug-1].js (collection page):

{post.images.map((post) => {
  console.log(post.image)
})}
// This div is OUTSIDE the map - 'post' here is still the collection!
<div>
  <Link href={`/photo/${encodeURIComponent(post.slug.current)}`}>
    <Image src={urlFor(post.image).auto('format').url()} />
  </Link>
</div>

The fix: Move your JSX inside the map function and return it, just like in your camera page:

{post.images.map((image) => {  // Rename to 'image' to avoid confusion
  return (
    <div sx={{
      '> a > div': {
        position: 'relative !important',
        height: 'auto',
        display: 'block',
        aspectRatio: '1 / 1',
      },
      '> a > div > img': {
        height: '100% !important',
        width: '100% !important',
        position: 'relative !important',
      }
    }}>
      <Link href={`/photo/${encodeURIComponent(image.slug.current)}`}>
        <a>
          <Image src={urlFor(image.image).auto('format').url()} layout="fill" objectFit="cover" />
        </a>
      </Link>
    </div>
  )
})}

The key changes:

  1. Added return statement inside the map
  2. Renamed the parameter from post to image to avoid confusion with the outer post variable
  3. Moved all the JSX inside the map function so it renders for each image

Your GROQ query looks correct - it's dereferencing the image references properly with "images": images[]->{image, slug}. The issue was purely in how you were rendering the data in React!

Show original thread
15 replies
(Pinging
user A
who helped me last time! If you’ve got any insight this time, I’d absolutely appreciate it! 👏)
I’ll be happy to take a look in the morning. 👍
Thank you so much!!
Thank you so much!!
When you run that GROQ query in Vision that’s in getStaticProps() in [slug].js, does it work? Perhaps even paring it down a bit might help to help get to the problem:

*[_type == "camera" && slug.current == $slug]{title, "photos": *[_type == 'photo' && references(^._id)]}[0]

// Params
{
  "slug": "<A_CAMERA_SLUG>"
}
Also, just to confirm, are you setting a reference to
_type: 'camera'
from the document of
_type: 'photo'
?
Thanks so much for your help! That page is actually working perfectly fine - it’s the collection query that I’m having trouble with:

export const getStaticProps = async ({ params }) => {
    const post = await sanityClient.fetch(`*[_type == "collection" && slug.current == $slug]{title, description, "images": images[]->{image, slug}}[0]`, { slug: params.slug })

    return {
        props: { post },
        revalidate: 30,
    }
}
While I can see the post objects that this returns in the console, and they seem to look visually identical to the ones logged in the camera page, the data is unavailable - which is making me think it’s something in how I’m working with this reference!

This
collection
document has an
images
field that is an array of references to
photo
documents.
Okay, thanks for the clarification. So [slug].js works fine but [slug-1].js doesn’t.

This 
collection
 document has an 
images
 field that is an array of references to 
photo
 documents.
Based on this, I’m curious about the
image
in your projection in
"images": images[]->{image, slug}
. Would you be willing to post the JSON you get back from this?

*[_type == "collection"]{..., "images": images[]->}[0]
Great! That’s helpful, thank you. Could you try this in your fetch in getStaticProps()?

*[_type == "collection" && slug.current == $slug]{title, description, "images": images[]{'image': image.asset->, slug}}[0]`, { slug: params.slug })
You can play with the naming, but it looks like you’ll want to destructure
images[].image.asset
.
Thanks for this! When I run this query the
images
array is filled with empty objects for some reason!
Oh. Sorry, I’m looking back at the code that produced response.json and you did destructure images[]. What does this give?

*[_type == "collection" && slug.current == $slug]{title, description, "images": images[]->{'image': image.asset->, slug}}[0]`, { slug: params.slug })
That did it, thank you so much!
I had also totally missed that my presentation logic was sitting outside my map function, which also wasn't helping!
Thanks again for all your help! I really appreciate it!
Great! 🙌 Happy to hear it.

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?