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
相关产品推荐
相关产品推荐

