基于许多内容引用使用 Gatsby 动态创建页面

Posted

技术标签:

【中文标题】基于许多内容引用使用 Gatsby 动态创建页面【英文标题】:Dynamically create pages with Gatsby based on many Contentful references 【发布时间】:2021-07-02 02:55:17 【问题描述】:

我目前正在使用 Gatsby 的 collection routes API 为一个简单的博客创建页面,其中的数据来自 Contentful。

例如,为每个博文类别创建一个页面:

-- src/pages/categories/contentfulBlogPost.category.js

export const query = graphql`
  query categoriesQuery($category: String = "") 
    allContentfulBlogPost(filter:  category:  eq: $category  ) 
      edges 
        node 
          title
          category
          description 
            description
          
        ...
        
      
    
  

...
[React component mapping all blogposts from each category in a list]
...

这工作正常。

但现在我希望每个博文有多个类别,所以我切换到 Contentful 的 references, many 内容类型,它允许一个字段有多个条目:

现在我对字段 category2 的 graphQL 查询的结果是每个博文的不同类别的数组:

查询:

query categoriesQuery 
  allContentfulBlogPost 
    edges 
      node 
        category2 
          id
          name
          slug
        
      
    
  

输出:


  "data": 
    "allContentfulBlogPost": 
      "edges": [
        
          "node": 
            "category2": [
              
                "id": "75b89e48-a8c9-54fd-9742-cdf70c416b0e",
                "name": "Test",
                "slug": "test"
              ,
              
                "id": "568r9e48-t1i8-sx4t8-9742-cdf70c4ed789vtu",
                "name": "Test2",
                "slug": "test-2"
              
            ]
          
        ,
        
          "node": 
            "category2": [
              
                "id": "75b89e48-a8c9-54fd-9742-cdf70c416b0e",
                "name": "Test",
                "slug": "test"
              
            ]
          
        ,
...

现在类别在数组中,我不知道如何:

编写一个查询变量来过滤类别名称; 使用 slug 字段作为路由来动态创建页面。

对于我正在做的博文作者:

  query authorsQuery($author__slug: String = "") 
    allContentfulBlogPost(filter:  author:  slug:  eq: $author__slug   ) 
      edges 
        node 
          id
          author 
            slug
            name
          
          ...
        
      ...
      

并使用src/pages/authors/contentfulBlogPost.author__slug.js 创建页面

我想我必须改用 createPages API。

【问题讨论】:

【参考方案1】:

您可以使用 Filesystem API 实现结果,类似这样的方法可能有效:

src/pages/category/contentfulBlogPost.category2__name.js

在这种情况下,这种方法似乎会导致一些警告,因为您可能会创建具有相同 URL (slug) 的重复页面,因为帖子可能包含多个重复的类别。

但是,我认为使用您所说的createPages API 更简洁,请记住,您需要处理类别以避免重复,因为它们是一对多 em> 关系。

exports.createPages = async ( graphql, actions ) => 
  const  createPage  = actions
  const result = await graphql(`
    query 
     allContentfulBlogPost 
        edges 
          node 
            category2 
              id
              name
              slug
            
          
        
      
    
  `)
  
  let categories=  slugs: [], names: [] ;

  result.data.allContentfulBlogPost.edges.map((node))=> 
   let  name, slug  = node.category2;
   // make some checks if needed here

    categories.slugs.push(slug);
    categories.names.push(name);

    return new Set(categories.slugs) && new Set(categories.names);
  );

  categories.slugs.forEach((category, index) => 
    let name = categories.names[index];

    createPage(
      path: `category/$category`,
      component: path.resolve(`./src/templates/your-category-template.js`),
      context: 
        name
      
    );
  );

代码非常不言自明。基本上,您正在定义一个空对象 (categories),其中包含两个数组 slugsnames

  let categories=  slugs: [], names: [] ;

之后,您只需遍历查询结果(result)并将字段值(nameslug 和其他如果需要)推送到前一个数组,进行所需的检查如果您愿意(避免推送空值或匹配某些正则表达式等)并返回 new Set 以删除重复项。

然后,您只需要循环使用createPage API 创建页面并通过上下文传递所需的数据:

  context: 
    name
  

由于冗余,这和做的一样:

  context: 
    name: name
  

因此,在您的模板中,您将获得pageContext props 中的名称。如果需要,将其替换为 slug,具体取决于您的情况和用例,方法完全相同。

【讨论】:

感谢您的详细解答!

以上是关于基于许多内容引用使用 Gatsby 动态创建页面的主要内容,如果未能解决你的问题,请参考以下文章

如何选择性地查询 gatsby Contentful Rich Text 中的引用?

基于Gatsby的React静态化实践

如何将 Gatsby 混合站点连接到 Apollo/Graphcool(或 Redux)?

在Gatsby JS中动态生成路由

如何从 JSON 文件在 Gatsby 中创建页面?

如何使用图像组件将图像动态添加到 Gatsby 中的页面?