Gatsby 的 GraphQL 查询 - 具有灵活内容模型的内容设置

Posted

技术标签:

【中文标题】Gatsby 的 GraphQL 查询 - 具有灵活内容模型的内容设置【英文标题】:GraphQL queries for Gatsby - Contentful setup with a flexible content model 【发布时间】:2019-01-20 12:46:41 【问题描述】:

我有一个 gatsby 网站,其中包含 contentful 插件graphql 查询(设置正常)。

[编辑] 我的 gatsby 设置使用 pageCreate 功能动态提取数据。并填充我的模板组件,即我在下面共享的根 graphql 查询。如果内容页面遵循以下查询中给出的结构,我可以使用设置创建多个页面。 [/编辑]

我的问题是关于我似乎遇到的一个限制,或者只是不知道足够的 grpahql 来理解这一点。

我的高级内容模型“BasicPageLayout”包含通过字段“Section”对其他内容类型的引用。因此,在“BasicPageLayout”中包含哪些内容类型以及添加它们的顺序方面,它是灵活的。

根页面查询

export const pageQuery = graphql`
query basicPageQuery 
contentfulBasicPageLayout(pageName: eq: "Home") 

    heroSection 
        parent 
            id
        
        ...HeroFields
    

    section1 
        parent 
            id
        
        ...ContentText

    

    section2 
        parent 
            id
        
        ...ContentTextOverMedia
    

    section3 
        parent 
            id
        
        ...ContentTextAndImage
    

    section4 
        parent 
            id
        
        ...ContentText
    
  

内容类型片段都存在于各自的 UI 组件中。 上述查询和设置工作正常。

现在,我对“Home”进行了硬编码,因为我无法创建灵活的可重用查询。我在创建模型时利用了 contentful 的灵活特性,但还没有找到一种方法在 graphql 查询中为其创建这种灵活性。

我所知道的: Graphql 查询是在运行时解析的,因此需要获取的所有内容都应该在该查询中。它不能是“动态的”。

问题: basicPageLayout 中的“Section”字段可以链接到任何内容类型。所以我们可以混合和匹配粒度级别的内容类型。如何添加内容类型片段(如 ContentTextAndImage 与 ContentText),使其适合该部分实例(查询中的“Section”字段)?

换句话说 我希望根查询获取可能有 4 个部分的“主页”数据,所有类型 - ContentTextOverMedia 以及可能也有 4 个部分但类型交替的“关于”数据 - ContentText 和 ContentTextAndImage

这是目标,因为我想通过在内容上混合匹配内容类型来创建内容(页面),而无需在每次创建新页面时更新代码。这就是为什么 Contentful 很有用并且首先被选中的原因。

到目前为止我的想法:

A.连续运行两个查询。一个获取每个部分的 parent.id 并保存内容类型信息。第二次使用适当的片段获取数据。

B.通过 Contentful API 分别获取 basicPageLayouts 内容实例(例如“Home”)的 JSON 文件,并使用该 JSON 文件创建要在每个实例中使用的 graphql 字符串(因此,Home、About 等不同的布局) 这需要更多的实验,不确定它是否可行,也可能比它需要的更复杂。

所以,请分享我正在探索的上述路径或我没有考虑使用 graphql 或 gatsby 功能的其他解决方案的想法。

这是我关于 SO btw 的第一个问题,我花了一些时间来完善它并尝试遵循指南,但请务必在 cmets 中给我反馈,这样即使您没有我的答案,我也可以改进题。 提前致谢。

【问题讨论】:

【参考方案1】:

如果我理解正确,您想根据来自 Contentful 的数据动态创建页面。

您可以使用 Gatsbyjs 节点 API 特别是 createPage 来实现这一点。

在您的gatsby-node.js 文件中,您可以拥有类似的内容

const fs = require('fs-extra')
const path = require('path')

exports.createPages = (graphql, boundActionCreators) => 
  const createPage = boundActionCreators
  return new Promise((resolve, reject) => 
    const landingPageTemplate = path.resolve('src/templates/landing-page.js')
    resolve(
      graphql(`
        
          allContentfulBesicPageLayout 
            edges 
              node 
                pageName
              
            
          
        
      `).then((result) => 
        if (result.errors) 
          reject(result.errors)
        
        result.data.allContentfulBesicPageLayout.edges.forEach((edge) => 
          createPage (
            path: `$edge.node.pageName`,
            component: landingPageTemplate,
            context: 
              slug: edge.node.pageName // this will passed to each page gatsby create
            
          )
        )
        return
      )
    )
  )

现在在你的src/templates/landing-page.js

import React,  Component  from 'react'
const LandingPage = (data) => 
    return (<div>Add you html here</div>)


export const pageQuery = graphql`
query basicPageQuery($pageName: String!) 
contentfulBasicPageLayout(pageName: eq:  $pageName) 

    heroSection 
        parent 
            id
        
        ...HeroFields
    

    section1 
        parent 
            id
        
        ...ContentText

    

    section2 
        parent 
            id
        
        ...ContentTextOverMedia
    

    section3 
        parent 
            id
        
        ...ContentTextAndImage
    

    section4 
        parent 
            id
        
        ...ContentText
    
  

注意$pageName 参数,这是在创建页面时传递给组件上下文的内容。 这样,您最终将创建任意数量的页面。 请注意:代码的反应部分没有经过测试,但我希望你明白。

更新: 要进行灵活的查询,而不是将内容类型作为单个 ref 字段,您可以拥有一个名为 section 的字段,您可以按您想要的顺序在其中添加您想要的部分。 您的查询将如下所示

    export const pageQuery = graphql`
    query basicPageQuery($pageName: String!) 
    contentfulBasicPageLayout(pageName: eq:  $pageName) 
       sections 
         ... on ContentfulHeroFields 
           internal 
              type
        
    
         

哈立德

【讨论】:

感谢您的回答哈立德。当我开始这个项目时,我看了你内容丰富的 + gatsby 系列,它非常有用,所以也谢谢你。澄清:我已经让 pageCreate 工作了,如果我将多个页面添加到内容完全相同的结构中,它会动态工作。问题在于查询结构的灵活性。对于其他页面,我可能想要具有不同内容类型的部分或不同顺序的部分,但希望使用相同的模板(布局),因为内容上的顺序/内容类型可能会经常更改。 啊,好吧,那么您可以拥有一个名为 section 的字段,而不是将您的内容类型作为单个 ref 字段,您可以按照您想要的顺序添加您想要的部分。我会更新答案 好的,所以一个字段(多参考?)包含按所需顺序的所有部分 - 这也适用于组织内容和传达顺序。但是,关于如何识别每个部分的值是什么(什么内容类型)以便将其字段放入查询中的问题仍然存在。由于必须在运行时知道这些内容类型字段。如果问题需要更多信息,请告诉我! 这是... on Contentful[YourSectionContentType] 的一部分,基于 internal.type 渲染块。我在这里做了类似的事情:github.com/Khaledgarbaya/chocolate-free-website/blob/master/src/… 啊,所以对于每个部分的值,通过对每个片段使用“打开”功能,覆盖了任何已定义内容类型的可能性。那太棒了!感谢您编辑答案。

以上是关于Gatsby 的 GraphQL 查询 - 具有灵活内容模型的内容设置的主要内容,如果未能解决你的问题,请参考以下文章

如何在带有 gatsby 的 graphql 查询中使用正则表达式

Gatsby:graphql 查询中的 gatsby-source-graphql 和 gatsby-plugin-sharp

Gatsby 具有自己查询的可重用组件

Gatsby 从数据中获取具有相对路径的图像文件夹

单个 GraphQL 查询中的多个源 (Gatsby)

gatsby-source-prismic-graphql 查询结构