Sanity GROQ查询异常:Web应用返回undefined,插件查询正常
问题:GROQ查询在Sanity插件中正常,但Next.js应用返回undefined
其他GROQ查询均可正常工作,但当前查询在Web应用中返回undefined,手动在Sanity GROQ VS插件中设置$slug变量却能成功获取目标数据。
相关代码
查询函数代码
export async function getPost(slug: string): Promise<BlogPost> { console.log('fetching post data'); const data = createClient(clientConfig).fetch( groq`*[_type == "blogPost" && slug.current == $slug][0]{ ..., author->, categories[]->, "mainImage": mainImage.asset-> url, 'slug': slug.current, title, description, }`, { slug: slug }, {cache: 'no-store'}, ) }
Sanity客户端配置
import {createClient} from 'next-sanity'; import {apiVersion, dataset, projectId} from '../env'; const config ={ projectId: projectId, dataset: dataset, apiVersion: apiVersion, useCdn: false, }; export default config;
环境变量配置
export const apiVersion = process.env.NEXT_PUBLIC_SANITY_API_VERSION || '2023-09-14' export const dataset = assertValue( process.env.NEXT_PUBLIC_SANITY_DATASET, 'Missing environment variable: NEXT_PUBLIC_SANITY_DATASET' ) export const projectId = assertValue( process.env.NEXT_PUBLIC_SANITY_PROJECT_ID, 'Missing environment variable: NEXT_PUBLIC_SANITY_PROJECT_ID' ) export const useCdn = false function assertValue<T>(v: T | undefined, errorMessage: string): T { if (v === undefined) { throw new Error(errorMessage) } return v }
页面组件代码
import React from 'react'; import { getPost } from '@/sanity/schemas/sanity-utils'; import Image from 'next/image'; import {BlogPost} from '@/typings'; type Props = { params: {post: string}; }; export default async function post({ params }: Props[]) { const slug = params.slug; const post = await getPost(slug); console.log(post); return ( <article className='px-10 pb-28'> <section className='space-y-2 border border-gray-500 text-white'> <div className='relative min-h-56 flex flex-col md:flex-row justify-between'> <picture className='absolute top-0 w-full h-full opacity-10'> <Image className='object-cover object-center mx-auto' src={post.mainImage} alt={post.author.name} fill /> </picture> <section className='p-5 bg-grey w-full'> <div className='flex flex-col md:flex-row justify-between gap-y-5'> <div> <h1 className='text-4xl font-extrabold'> {post.title} </h1> <p> {new Date(post._createdAt).toLocaleDateString()} </p> </div> <div className='flex items-center space-x-2'> <Image className='rounded-full' src={post.author.image} alt={post.author.name} height={40} width={40} /> <div className='w-54'> <h3 className='text-lg font-bold'> {post.author.name} </h3> <div> {/* author bio */} </div> </div> </div> </div> </section> </div> </section> </article> ) }
已尝试修改$slug的多种写法,调整页面Props定义,但问题仍未解决。
解决方案
1. 修复查询函数的返回值问题
getPost函数未返回fetch获取到的数据,这是返回undefined的核心原因,需在函数末尾添加返回语句:
export async function getPost(slug: string): Promise<BlogPost> { console.log('fetching post data'); const data = createClient(clientConfig).fetch( groq`*[_type == "blogPost" && slug.current == $slug][0]{ ..., author->, categories[]->, "mainImage": mainImage.asset-> url, 'slug': slug.current, title, description, }`, { slug: slug }, {cache: 'no-store'}, ); // 必须返回获取到的数据 return data; }
2. 修复页面组件的Props类型与字段匹配问题
- Props类型定义错误:
Props[]应为Props(非数组类型) params字段名不匹配:定义的是post,但代码中使用params.slug,需统一字段名(需和路由文件名对应,比如路由是[slug].tsx则字段为slug):
import React from 'react'; import { getPost } from '@/sanity/schemas/sanity-utils'; import Image from 'next/image'; import {BlogPost} from '@/typings'; // 匹配路由定义的动态字段名 type Props = { params: {slug: string}; }; // Props无需数组类型 export default async function post({ params }: Props) { // 字段名匹配后正确获取slug const slug = params.slug; const post = await getPost(slug); console.log(post); return ( <article className='px-10 pb-28'> <section className='space-y-2 border border-gray-500 text-white'> <div className='relative min-h-56 flex flex-col md:flex-row justify-between'> <picture className='absolute top-0 w-full h-full opacity-10'> <Image className='object-cover object-center mx-auto' src={post.mainImage} alt={post.author.name} fill /> </picture> <section className='p-5 bg-grey w-full'> <div className='flex flex-col md:flex-row justify-between gap-y-5'> <div> <h1 className='text-4xl font-extrabold'> {post.title} </h1> <p> {new Date(post._createdAt).toLocaleDateString()} </p> </div> <div className='flex items-center space-x-2'> <Image className='rounded-full' src={post.author.image} alt={post.author.name} height={40} width={40} /> <div className='w-54'> <h3 className='text-lg font-bold'> {post.author.name} </h3> <div> {/* author bio */} </div> </div> </div> </div> </section> </div> </section> </article> ) }
3. 额外检查点
- 确认Next.js动态路由文件名正确,比如
[slug].tsx,确保params.slug能获取到对应值 - 在页面组件中打印
params,确认传递的slug值是否正确:console.log('params:', params);
内容的提问来源于stack exchange,提问作者lorenzo washington
相关产品推荐
相关产品推荐

