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

Gatsby+Sanity静态构建异步数据获取失败问题求助

解决Gatsby+Sanity静态构建后显示Loading的问题

嘿,我完全懂你现在的困扰——开发环境里功能一切正常,Netlify构建完却一直卡在Loading状态,这根本原因是你当前用的是客户端侧异步数据获取,和Gatsby静态构建的逻辑不匹配。让我一步步帮你搞定这个问题:

为什么会出现这个问题?

你现在用useSWR发起的请求,是在组件挂载后(浏览器执行JS阶段)才触发的。开发环境中Gatsby的热加载机制会模拟客户端环境,所以能正常拿到数据;但Netlify构建静态站点时,只会执行构建阶段的代码,不会运行客户端的useEffect或useSWR这类异步逻辑,所以最终生成的静态页面里只有Loading文本,直到用户打开页面、浏览器执行JS后才会发起请求,这就导致了生产环境的加载异常。

正确思路:在Gatsby构建阶段预取所有数据

Gatsby的核心优势就是静态生成时提前拉取所有需要的数据,我们需要改用Gatsby的内置数据方案,把Sanity的数据在构建阶段同步到Gatsby的数据层,然后用GraphQL直接查询,彻底避免客户端异步请求。

第一步:确认Sanity数据源插件配置

首先确保你已经安装并配置了gatsby-source-sanity,它会把Sanity的数据同步到Gatsby的GraphQL数据层。你的gatsby-config.js配置大概是这样的:

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-sanity`,
      options: {
        projectId: `你的Sanity项目ID`,
        dataset: `你的数据集名称`,
        watchMode: true, // 开发环境自动同步数据
        overlayDrafts: true,
      },
    },
  ],
}

第二步:根据组件类型选择数据获取方式

情况1:如果是页面组件——用pageQuery

页面组件可以直接导出GraphQL查询,Gatsby会在构建时自动执行这个查询,把数据作为props传给页面:

import React from "react"
import { graphql } from "gatsby"
import BlockCarouselBlog from "../components/BlockCarouselBlog"

export default function BlogPage({ data }) {
  // 假设你的block数据来自页面配置或其他查询
  const block = { itemAmount: 5 }
  return (
    <div>
      <BlockCarouselBlog block={block} blogData={data.allSanityBlog.nodes} />
    </div>
  )
}

// 构建阶段执行的查询,提前拉取所有博客数据
export const pageQuery = graphql`
  query BlogPageQuery {
    allSanityBlog(sort: { fields: _createdAt, order: ASC }) {
      nodes {
        _id
        title
        excerpt
        // 这里列出你需要的所有博客字段
      }
    }
  }
`
情况2:如果是子组件——用useStaticQuery(静态场景)

如果你的子组件不需要动态参数,可以用useStaticQuery钩子直接在组件内执行构建阶段的查询:

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import BlockCarousel from "../blockCarousel/blockCarousel"

const BlockCarouselBlog = ({ block }) => {
  const defaultLimit = 10
  const limit = block.itemAmount ? block.itemAmount : defaultLimit
  
  // 构建阶段直接查询数据,无需客户端请求
  const data = useStaticQuery(graphql`
    query BlogCarouselQuery {
      allSanityBlog(sort: { fields: _createdAt, order: ASC }, limit: 10) {
        nodes {
          _id
          title
          excerpt
        }
      }
    }
  `)

  // 根据需要的数量切片数据
  const filteredBlogs = data.allSanityBlog.nodes.slice(0, limit)
  block.blocks = filteredBlogs

  return <BlockCarousel block={block} />
}

export default BlockCarouselBlog

⚠️ 注意:useStaticQuery不支持动态参数(比如直接把limit作为变量传入查询),如果你的block.itemAmount是动态变化的,建议用页面组件查询全量数据,再通过props传给子组件的方案,灵活性更高。

最后调整组件逻辑

彻底移除原来的useSWR相关代码,改用上面的构建阶段查询方式。这样Netlify构建时会提前拉取所有需要的博客数据,生成的静态页面直接包含完整内容,不会再出现Loading状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 07:04:08