Multiple page components for the same node type in Gatsby
How can you achieve different page layouts for content with the same content node type but varying content types?
In yesterday's email, we looked at a solution involving multiple page templates. Today we'll look at achieving the same with multiple page components. And tomorrow we'll look at how to use parrot pages by making our own MarkdownRemark parent nodes 🤯
Multiple Page Components
For the multiple page components approach, we can create the MarkdownRemark pages using either the createPages
extension point or the File Sytem Route API.
Then inside our root page component, we'll make sure to render the correct page component for our content type and pass on the queried data.
// src/pages/{MarkdownRemark.fields__slug}.js
import React from "react";
import { graphql } from "gatsby";
import PostTemplate from "../components/post-page";
import ProjectTemplate from "../components/project-page";
const components = {
post: PostTemplate,
project: ProjectTemplate,
};
const RemarkPage = ({ data, ...props }) => {
const contentType = data.markdownRemark?.parent.sourceInstanceName;
const Component = components[contentType]; // 👈
return <Component data={data.markdownRemark} {...props} />;
};
export default RemarkPage;
// PostFragment defineded in the ../components/post-page.js file
// ProjectFragment defined in ../components/project-page.js file
export const query = graphql`
query ($id: String!) {
markdownRemark(id: { eq: $id }) {
id
...ProjectFragment
...PostFragment
parent {
... on File {
sourceInstanceName
}
}
}
}
`;
If GraphQL Fragments are new to you, check out the Using GraphQL Fragments article by Gatsby for more information.
Same as yesterday, the sourceInstanceName
used comes from configuring your gatsby-source-filesystem
with the name
option.
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content/posts`,
name: "post",
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content/projects`,
name: "project",
},
},
],
};
And the slug is created using the onCreateNode
extension point.
// gatsby-node.js
const { createFilePath } = require("gatsby-source-filesystem");
exports.onCreateNode = (gatsbyUtils) => {
const { actions, node, getNode, reporter } = gatsbyUtils;
const { createNodeField } = actions;
if (node.internal.type === "MarkdownRemark") {
const slug = createFilePath({ node, getNode });
const parent = getNode(node.parent);
createNodeField({
name: "slug",
node,
value: parent.sourceInstanceName + slug,
});
reporter.info(`Create slug ${slug}`);
}
};
How do you solve different page layouts for content with the same content node type but varying content types?
All the best,
Queen Raae