【问题标题】:GraphQL queries for Gatsby - Contentful setup with a flexible content modelGatsby 的 GraphQL 查询 - 具有灵活内容模型的内容设置
【发布时间】: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 中给我反馈,这样即使您没有我的答案,我也可以改进题。 提前致谢。

【问题讨论】:

    标签: graphql gatsby contentful


    【解决方案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/…
    • 啊,所以对于每个部分的值,通过对每个片段使用“打开”功能,覆盖了任何已定义内容类型的可能性。那太棒了!感谢您编辑答案。
    猜你喜欢
    • 2019-07-21
    • 2020-12-03
    • 1970-01-01
    • 2011-02-14
    • 2020-05-01
    • 2017-01-07
    • 1970-01-01
    • 2020-11-02
    • 2019-06-16
    相关资源
    最近更新 更多