You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从SanityClient的图片数组获取首张图片?排查语法报错

问题:Sanity GROQ查询语法错误及图片展示异常

我有多个set集合,希望在网页中展示每个set的首张图片作为对应画廊的跳转链接,计划获取每个set图片数组中的首张图片,但目前遇到报错:description: "expected '}' following object body"。

现有React代码

import React, { useState, useEffect } from 'react';
import { client, urlFor } from '../lib/client';
import { Header, Footer } from '../components';
import Link from 'next/link';

const gallery = () => {

const [ galleryData, setGalleryData ] = useState(null);

useEffect(() => {
  client.fetch(
    `*[_type == 'set']{
      set_name,
      set_images[]->{
        image{->asset{
          _id,
          url
        }}
      }
    }`
  ).then((data) => setGalleryData(data))
  .catch(err => console.error(err))
})

  return (
    <div>
    <Header />
    <main className="main-gallery"> 
      <div className="title">
          <div className="title-line-left"></div>
          <h2>gallery</h2> 
          <div className="title-line-right"></div>
      </div>
      <div className="categories">
          <ul className="categories-container">
            {galleryData && galleryData.map((set, index) => (
                <li key={index}>
                    <Link href="/sets"><img src={urlFor(set.set_images.image[0]).auto('format').url()} alt={set.set_name}/></Link>
                </li>
            ))}
          </ul>
      </div>
    </main>
    <Footer />
    </div>
  )
}

Sanity Schema定义

export default {
name: 'set',
type: 'document',
title: 'Set',
fields: [
    {
        name: 'set_name',
        type: 'string',
        title: 'Set Name',
    },
    {
        name: 'set_images',
        type: 'array',
        title: 'Set Images',
        of: [
            {
                name: 'image',
                type: 'image',
                title: 'Image',
                options: {
                    hotspot: true,
                },
                fields: [
                    {
                        name: 'alt',
                        type: 'string',
                        title: 'Alternative Text',
                        options: {
                            isHighlighted: true
                        }
                    },
                    {
                        name: 'name',
                        type: 'string',
                        title: 'Name',
                        options: {
                            isHighlighted: true
                        }
                    },
                    {
                        name: 'date',
                        type: 'string',
                        title: 'Date',
                        options: {
                            isHighlighted: true
                        }
                    },
                    {
                        name: 'size',
                        type: 'string',
                        title: 'Size',
                        options: {
                            isHighlighted: true
                        }
                    },
                    {
                        name: 'materials',
                        type: 'string',
                        title: 'Materials',
                        options: {
                            isHighlighted: true
                        }
                    },
                ]
            },
        ]
    },
    {
        name: 'slug',
        title: 'Slug',
        type: 'slug',
        options: {
            source: 'set_name'
        }
    }
]
}

解决方案

1. 修复GROQ查询语法错误

报错根源是GROQ查询结构错误:根据Schema,set_images是image类型的数组,每个数组元素本身就是image对象,不需要额外嵌套image字段查询。正确的查询应该直接获取image的asset和自定义字段:

*[_type == 'set']{
  set_name,
  slug,
  set_images[]{
    asset->{_id, url},
    alt
  }
}

2. 修正图片路径获取逻辑

原代码中set.set_images.image[0]写法错误,set_images是数组,直接取第一个元素即可,同时要处理数组为空的边界情况避免报错。另外,跳转链接应指向对应set的详情页,用slug参数代替固定路径:

{galleryData && galleryData.map((set, index) => (
  <li key={index}>
    {set.set_images.length > 0 && (
      <Link href={`/sets/${set.slug.current}`}>
        <img 
          src={urlFor(set.set_images[0]).auto('format').url()} 
          alt={set.set_images[0].alt || set.set_name}
        />
      </Link>
    )}
  </li>
))}

3. 完善useEffect避免无限渲染

原useEffect没有依赖数组,会导致组件无限重复执行fetch请求,添加空数组作为依赖,确保只在组件挂载时执行一次:

useEffect(() => {
  client.fetch(
    // 上面修正后的GROQ查询
  ).then((data) => setGalleryData(data))
  .catch(err => console.error(err))
}, []) // 添加空依赖数组

修复后的完整React代码

import React, { useState, useEffect } from 'react';
import { client, urlFor } from '../lib/client';
import { Header, Footer } from '../components';
import Link from 'next/link';

const Gallery = () => {
  const [galleryData, setGalleryData] = useState(null);

  useEffect(() => {
    client.fetch(
      `*[_type == 'set']{
        set_name,
        slug,
        set_images[]{
          asset->{_id, url},
          alt
        }
      }`
    ).then((data) => setGalleryData(data))
    .catch(err => console.error(err))
  }, [])

  return (
    <div>
      <Header />
      <main className="main-gallery"> 
        <div className="title">
          <div className="title-line-left"></div>
          <h2>gallery</h2> 
          <div className="title-line-right"></div>
        </div>
        <div className="categories">
          <ul className="categories-container">
            {galleryData && galleryData.map((set, index) => (
              <li key={index}>
                {set.set_images.length > 0 && (
                  <Link href={`/sets/${set.slug.current}`}>
                    <img 
                      src={urlFor(set.set_images[0]).auto('format').url()} 
                      alt={set.set_images[0].alt || set.set_name}
                    />
                  </Link>
                )}
              </li>
            ))}
          </ul>
        </div>
      </main>
      <Footer />
    </div>
  )
}

export default Gallery;

内容的提问来源于stack exchange,提问作者meeppeem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 17:15:36