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

如何用GROQ查询获取90天前的Sanity博客文章?

问题分析与解决方案

你的代码存在两个核心问题导致页面无法渲染内容:GROQ查询的逻辑与语法错误,以及客户端组件使用async/await的兼容性问题。

1. 修复GROQ查询

原查询的逻辑完全颠倒:你需要获取发布时间超过90天的文章,应该筛选创建时间早于「当前时间减去90天」的内容,而非晚于。同时查询缺少必要括号,导致排序逻辑无法正确生效。

错误查询:

*[_type == 'post' && dateTime(_createdAt) >= dateTime(now()) - 60 * 60 * 24 * 90 | order(_createdAt desc)]

正确查询:

*[_type == 'post' && dateTime(_createdAt) <= dateTime(now()) - 60 * 60 * 24 * 90] | order(_createdAt desc)
  • 将>=改为<=,表示文章创建时间早于90天前的时间节点
  • 给过滤条件添加括号,确保排序操作| order(_createdAt desc)作用于整个过滤结果集

2. 解决客户端组件的async/await问题

你添加了"use client"指令,但Next.js的客户端组件不支持直接将默认导出的组件声明为async函数,这会导致组件无法正常渲染。你有两种解决方式:

方案一:移除"use client",使用服务器组件

服务器组件天然支持async/await数据获取,适合静态或动态渲染的页面:

// 移除顶部的 "use client" 指令
import React from 'react'
import { client } from "../lib/sanity"
import { Post } from "../lib/interface"
import Link from "next/link";
import { PortableText } from '@portabletext/react';
import Image from "next/image";

async function getData() {
  const query = `*[_type == 'post' && dateTime(_createdAt) <= dateTime(now()) - 60 * 60 * 24 * 90] | order(_createdAt desc)`;
  const data = await client.fetch(query);
  console.log(data)
  return data;
}

export const revalidate = 60

export default async function movies() {
  const data = (await getData()) as Post[];

  return (
    <div className="xl:divide-y xl:divide-gray-200 xl:dark:divide-gray-700">
      <header className="pt-6 xl:pb-6">
        <div className="space-y-1 text-center">
          <div>
            <h1 className="text-3xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 sm:text-4xl sm:leading-10 md:text-5xl md:leading-14">
              Movies
            </h1>
          </div>
        </div>
      </header>
    
      <div className="divide-y divide-gray-200 pb-7 dark:divide-gray-700 xl:divide-y-0">
        <div className="divide-y divide-gray-200 dark:divide-gray-700 xl:col-span-3 xl:row-span-2 xl:pb-0">
          <div className="prose max-w-none pb-8 pt-10 dark:prose-invert prose-lg">
            <ul>
              {data.map((post) => (
                <li key={post._id} className="py-4">
                  <article className="space-y-2 xl:grid xl:grid-cols-4 xl:items-baseline xl:space-y-0">
                    <div>
                      <p className="text-base font-medium leading-6 text-teal-500">
                        {new Date(post._createdAt).toISOString().split('T')[0]}
                      </p>
                    </div>
                      <Link 
                        href={`/post/${post.slug.current}`} 
                        prefetch 
                        className="space-y-3 xl:col-span-3"
                      >
                    <div>
                      <h3 className="text-2xl font-bold leading-8 tracking-tight text-gray-900 dark:text-gray-100">
                        {post.title}  
                      </h3>
                    </div>
    
                      <p className="prose max-w-none text-gray-500 dark:text-gray-400 line-clamp-2">
                        {post.overview}
                      </p>
                      </Link>
                  </article>
                </li>
              ))}
            </ul>
          </div>
        </div>
      </div>  
    </div>
  )
}

方案二:保留"use client",使用客户端数据获取库(如SWR)

如果必须使用客户端组件(比如需要交互逻辑),可以用SWR处理数据获取:

"use client"

import React from 'react'
import { client } from "../lib/sanity"
import { Post } from "../lib/interface"
import Link from "next/link";
import { PortableText } from '@portabletext/react';
import Image from "next/image";
import useSWR from 'swr'

const fetcher = async () => {
  const query = `*[_type == 'post' && dateTime(_createdAt) <= dateTime(now()) - 60 * 60 * 24 * 90] | order(_createdAt desc)`;
  return client.fetch(query);
}

export default function movies() {
  const { data, error } = useSWR('old-posts', fetcher, {
    revalidateOnFocus: false,
    refreshInterval: 60000 // 对应原revalidate的60秒
  })

  if (error) return <div>加载失败</div>
  if (!data) return <div>加载中...</div>
  const posts = data as Post[]

  return (
    <div className="xl:divide-y xl:divide-gray-200 xl:dark:divide-gray-700">
      <header className="pt-6 xl:pb-6">
        <div className="space-y-1 text-center">
          <div>
            <h1 className="text-3xl font-extrabold leading-9 tracking-tight text-gray-900 dark:text-gray-100 sm:text-4xl sm:leading-10 md:text-5xl md:leading-14">
              Movies
            </h1>
          </div>
        </div>
      </header>
    
      <div className="divide-y divide-gray-200 pb-7 dark:divide-gray-700 xl:divide-y-0">
        <div className="divide-y divide-gray-200 dark:divide-gray-700 xl:col-span-3 xl:row-span-2 xl:pb-0">
          <div className="prose max-w-none pb-8 pt-10 dark:prose-invert prose-lg">
            <ul>
              {posts.map((post) => (
                <li key={post._id} className="py-4">
                  <article className="space-y-2 xl:grid xl:grid-cols-4 xl:items-baseline xl:space-y-0">
                    <div>
                      <p className="text-base font-medium leading-6 text-teal-500">
                        {new Date(post._createdAt).toISOString().split('T')[0]}
                      </p>
                    </div>
                      <Link 
                        href={`/post/${post.slug.current}`} 
                        prefetch 
                        className="space-y-3 xl:col-span-3"
                      >
                    <div>
                      <h3 className="text-2xl font-bold leading-8 tracking-tight text-gray-900 dark:text-gray-100">
                        {post.title}  
                      </h3>
                    </div>
    
                      <p className="prose max-w-none text-gray-500 dark:text-gray-400 line-clamp-2">
                        {post.overview}
                      </p>
                      </Link>
                  </article>
                </li>
              ))}
            </ul>
          </div>
        </div>
      </div>  
    </div>
  )
}

3. 额外检查点

  • 确认Sanity客户端client配置正确,能正常连接到你的数据集
  • 检查Post接口是否包含_id、_createdAt、slug.current、title、overview这些字段,确保类型匹配
  • 打开浏览器控制台,查看是否有报错信息,帮助定位其他潜在问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:20:54