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

Gatsby渲染Strapi动态区块时GraphQL查询报错(blocks未定义)

问题:动态生成页面中BlocksRenderer报错“无法访问属性‘map’,blocks未定义”

我用Strapi做无头CMS,Gatsby+GraphQL构建前端,写了BlocksRenderer组件渲染Strapi的动态区块,但通过gatsby-node.js动态生成slug页面时,BlocksRenderer报错blocks未定义,无法执行map方法。

问题根源分析

1. PageLayout组件的查询逻辑错误

原PageLayout用useStaticQuery查询了所有Strapi页面(allStrapiPage),但直接从allStrapiPage取Blocks完全错误——allStrapiPage是包含所有页面的集合,结构为{ edges: [{ node: 单个页面数据 }] },根本没有直接的Blocks属性。而且动态页面需要根据当前页面的slug匹配对应数据,静态查询无法实现动态匹配。

2. gatsby-node.js的页面数据传递缺失

原gatsby-node.js存在两个问题:

  • 查询allStrapiPage时未请求Blocks字段,导致后续无法获取区块数据
  • 仅传递pagePath到上下文,没有提供足够信息让模板查询对应页面的完整数据

修复方案

第一步:修正gatsby-node.js,确保获取并传递页面数据

更新查询语句以包含Blocks字段,并将slug传递给模板上下文:

const path = require('path')

exports.createPages = async ({ graphql, actions, reporter }) => {
    const { createPage } = actions

    const result = await graphql(
        `
        query {
            allStrapiPage {
                edges {
                    node {
                        Slug
                        Name
                        Blocks {
                          __typename
                          ... on STRAPI__COMPONENT_LAYOUT_ELEMENTS_MULTIPLE_CALLOUT {
                            id
                            MultipleCalloutItem {
                              id
                              Heading
                              Description
                            }
                          }
                          ... on STRAPI__COMPONENT_LAYOUT_ELEMENTS_SIMPLE_PARAGRAPH {
                            id
                            Text
                          }
                          ... on STRAPI__COMPONENT_LAYOUT_ELEMENTS_SPLIT_FEATURE {
                            id
                            Heading
                            Description
                            mediaAlignment
                            Media {
                              id
                              mime
                              localFile {
                                childImageSharp {
                                  gatsbyImageData
                                }
                              }
                              alternativeText
                            }
                          }
                          ... on STRAPI__COMPONENT_MEDIA_ELEMENT_HERO {
                            id
                            Heading
                            Description
                            Media {
                              id
                              mime
                              alternativeText
                              localFile {
                                url
                              }
                            }
                          }
                        }
                    }
                }
            }
        }
    `
    )

    if (result.errors) {
        reporter.panicOnBuild(`Error while running GraphQL Query`)
        return
    }

    const pageTemplate = path.resolve(`./src/layouts/page-layout.js`)
    result.data.allStrapiPage.edges.forEach(({ node }) => {
        createPage({
            path: node.Slug,
            component: pageTemplate,
            context: {
                slug: node.Slug
            },
        })
    })
}

第二步:重写PageLayout组件,使用页面查询获取对应数据

改用Gatsby的页面查询(而非静态查询),通过slug匹配当前页面:

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
import BlocksRenderer from "../components/blocks-renderer"

const PageLayout = ({ data }) => {
    const { Name, Blocks } = data.strapiPage

    return (
        <Layout>
            <h1>{Name}</h1>
            <BlocksRenderer blocks={Blocks} />
        </Layout>
    )
}

export const query = graphql`
    query($slug: String!) {
        strapiPage(Slug: { eq: $slug }) {
            Name
            Blocks {
                ...Blocks
            }
        }
    }
`

export default PageLayout

第三步:给BlocksRenderer添加空值保护

避免因blocks为undefined或非数组导致报错:

const BlocksRenderer = ({ blocks }) => {
    if (!blocks || !Array.isArray(blocks)) {
        return null
    }
    
    return (
        <div>
            {blocks.map((block, index) => (
                <Block key={`${index}${block.__typename}`} block={block} />
            ))}
        </div>
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 08:57:14