在Gatsby.js中以编程方式创建多种类型的页面 [英] Programmatically create multiple types of pages in Gatsby.js

查看:49
本文介绍了在Gatsby.js中以编程方式创建多种类型的页面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用GatsbyJS建立一个网站.我在两个不同的文件夹中有markdown文件:/content/collections /content/posts ,我希望Gatsby为每个markdown文件创建一个页面,并带有各自的模板(collection.js和post.js).

I'm building a website with GatsbyJS. I have markdown files in two different folders: /content/collections and /content/posts and I want Gatsby to create a page for each markdown file, with the respective template (collection.js and post.js).

所以我在我的gatsby-node.js文件中写了这个:

So I wrote this in my gatsby-node.js file:

const path = require('path');
const { createFilePath } = require('gatsby-source-filesystem');
exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions;
  if (node.internal.type === 'MarkdownRemark') {
    const longSlug = createFilePath({ node, getNode, basePath: 'content' });
    const slug = longSlug.split('/');
    createNodeField({
      node,
      name: 'slug',
      value: `/${slug[slug.length - 2]}/`,
    });
  }
};

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions;
  const result = await graphql(`
    query {
      allFile(filter: {relativeDirectory: {eq: "collections"}}) {
        edges {
          node {
            childMarkdownRemark {
              fields {
                slug
              }
            }
          }
        }
      }
    }
  `);
  result.data.allFile.edges.forEach(({ node }) => {
    createPage({
      path: node.childMarkdownRemark.fields.slug,
      component: path.resolve('./src/templates/collection.js'),
      context: {
        slug: node.childMarkdownRemark.fields.slug,
      },
    });
  });
};

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions;
  const result = await graphql(`
    query {
      allFile(filter: {relativeDirectory: {eq: "posts"}}) {
        edges {
          node {
            childMarkdownRemark {
              fields {
                slug
              }
            }
          }
        }
      }
    }
  `);
  result.data.allFile.edges.forEach(({ node }) => {
    createPage({
      path: node.childMarkdownRemark.fields.slug,
      component: path.resolve('./src/templates/post.js'),
      context: {
        slug: node.childMarkdownRemark.fields.slug,
      },
    });
  });
};

认为它将起作用.它确实适用于我输入的第二种类型.(在这种情况下,它创建了帖子,但不创建集合.如果我颠倒了调用createPages的顺序,它将交换,但它从不创建所有主题)

Thinking that it would work. It does work for the second type that I put in. (in this case it creates the posts, but not the collections. If I invert the order in which I call createPages it swaps, but it never creates all of them)

这是我在控制台中看到的错误:

This is the error that I get in the console:

warning The GraphQL query in the non-page component "/Users/matteocarpi/Documents/Web/Ledue/src/templates/collection.js" will not be run.
Exported queries are only executed for Page components. It's possible you're
trying to create pages in your gatsby-node.js and that's failing for some
reason.

If the failing component(s) is a regular component and not intended to be a page
component, you generally want to use a <StaticQuery> (https://gatsbyjs.org/docs/static-query)
instead of exporting a page query.

If you're more experienced with GraphQL, you can also export GraphQL
fragments from components and compose the fragments in the Page component
query and pass data down into the child component — https://graphql.org/learn/queries/#fragments

这两个模板非常相似:

import React from 'react';

import { graphql } from 'gatsby';
import PropTypes from 'prop-types';

const Post = ({data}) => {
  return (
    <div>
      <h1>{data.postData.frontmatter.title}</h1>
    </div>
  );
};

export default Post;

export const query = graphql`
query PostData($slug: String!) {
  postData: markdownRemark(fields: {slug: {eq: $slug}}) {
    frontmatter {
      title
    }
  }
}
`;

Post.propTypes = {
  data: PropTypes.node,
};

import React from 'react';

import { graphql } from 'gatsby';
import PropTypes from 'prop-types';

const Collection = ({data}) => {
  return (
    <div>
      <h1>{data.collectionData.frontmatter.title}</h1>
    </div>
  );
};

export default Collection;

export const query = graphql`
query CollectionData($slug: String!) {
  collectionData: markdownRemark(fields: {slug: {eq: $slug}}) {
    frontmatter {
      title
    }
  }
}
`;

Collection.propTypes = {
  data: PropTypes.node,
};

我尝试在

I tried refactoring all of the gatsby-node.js file following this answer but I end up in the same situation.

我在哪里弄错了?

推荐答案

问题是您正在用第二个函数声明覆盖第一个函数声明.像这样:

The issue is that you're overriding your first function declaration with the second. A bit like this:

var a = "hello"
a = "world"

相反,您应该执行所有查询,并对要在单个函数中创建的所有页面调用 createPage ,如下所示:

Instead you should do all of your querying and call createPage for all pages you want to create in a single function, something like this:

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions;

  const collections = graphql(`
    query {
      allFile(filter: {relativeDirectory: {eq: "collections"}}) {
        edges {
          node {
            childMarkdownRemark {
              fields {
                slug
              }
            }
          }
        }
      }
    }
  `).then(result => {
    result.data.allFile.edges.forEach(({ node }) => {
      createPage({
        path: node.childMarkdownRemark.fields.slug,
        component: path.resolve('./src/templates/collection.js'),
        context: {
          slug: node.childMarkdownRemark.fields.slug,
        },
      });
    });
  })

  const posts = graphql(`
    query {
      allFile(filter: {relativeDirectory: {eq: "posts"}}) {
        edges {
          node {
            childMarkdownRemark {
              fields {
                slug
              }
            }
          }
        }
      }
    }
  `).then(result => {
    result.data.allFile.edges.forEach(({ node }) => {
      createPage({
        path: node.childMarkdownRemark.fields.slug,
        component: path.resolve('./src/templates/post.js'),
        context: {
          slug: node.childMarkdownRemark.fields.slug,
        },
      });
    });
  })

  return Promise.all([collections, posts])
};

这篇关于在Gatsby.js中以编程方式创建多种类型的页面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆