GraphQL queries for Gatsby - Contentful setup with a flexible content model

妖精的绣舞 提交于 2019-12-09 07:20:10

问题


I have a gatsby site with the contentful plugin and graphql queries (setup is working).

[EDIT] My gatsby setup pulls data dynamically using the pageCreate feature. And populates my template component, the root graphql query of which I've shared below. I can create multiple pages using the setup if the pages on contentful follow the structure given in the below query. [/EDIT]

My question is about a limitation I seemed to have come across or just don't know enough grpahql to understand this yet.

My high level content model 'BasicPageLayout' consists of references to other content types through the field 'Section'. So, it's flexible in terms of which content types are contained in the 'BasicPageLayout' and the order in which they are added.

Root page query

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
    }
  }
}

The content type fragments all live in the respecitve UI components. The above query and setup are working.

Now, I have "Home" Hard coded because I'm having trouble creating a flexible reusable query. I'm taking advantage of contentful's flexible nature when creating the models, but haven't found a way to create that flexibility in the graphql query for it.

What I do know: Graphql query is resolved at run time, so everything that needs to be fetched should be in that query. It can't be 'dynamic'.

Issue: The 'Section' fields in the basicPageLayout can link to any content type. So we can mix and match the granular level content types. How do I add the content type fragment (like ContentTextAndImage vs ContentText) so it is appropriate for that section instance ('Section' field in the query)?

In other words I'd like the root query to get 'Home' data which might have 4 sections, all of type - ContentTextOverMedia as well as 'About ' data that might have also have 4 sections but with alternating types - ContentText and ContentTextAndImage

This is the goal because I want to create content (Pages) by mix-matching content types on contentful, without needing to update the code each time a new Page is created. Which is why Contentful is useful and was picked in the first place.

My ideas so far:

A. Run two queries, in series. One fetches the parent.id on each section and that holds the content type info. Second fetches the data using the appropriate fragment.

B. Fetch the JSON file of the basicPageLayouts content instance (such as 'Home') separately through Contentful API, and using that JSON file create the graphql string to be used in each instance (So, different layout for Home, About, and so on) This needs more experimentation, not sure if it's viable, could also be more complex then it needs to be.

So, please share thoughts on the above paths that I'm exploring or another solution that I haven't considered using graphql or gatsby's features.

This is my first question on SO btw, I've spent some time on refining it and trying to follow the guidelines but please do give me feedback in comments so I can improve even if you don't have an answer to my question. Thanks in advance.


回答1:


If I understood correctly you want to create pages dynamically from the data coming from Contentful.

You can achieve this using the Gatsbyjs Node API specifically createPage.

In your gatsby-node.js file you can have something like this

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
      })
    )
  })
}

Now in your 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
    }
  }
}

note the $pageName param that's what was passed to the component context when creating a page. This way you will end up creating as many pages as you want. Please note: the react part of the code was not tested but I hope you get the idea.

Update: To have a flexible query you instead of having your content Types as single ref field, you can have one field called sections and you can add the section you want there in the order you desire. Your query will look like this

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

}

Khaled



来源:https://stackoverflow.com/questions/51828234/graphql-queries-for-gatsby-contentful-setup-with-a-flexible-content-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!