Creating a post’s page in GatsbyJS

Post page component

Create a component for post page (temporary with basic jsx w/o any data)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import React from "react"

import Layout from "./Layout"

const PostLayout = () => {
  return (
    <Layout>
      <h1>Some Post</h1>
    </Layout>
  )
}

export default PostLayout

gatsby-node.ts

In gatsby-node.ts you should use createPages GatsbyJS method and set path to this component

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { GatsbyNode } from "gatsby"
import path from "path"
import { AllMarkdownRemark } from "./src/types"

const createPages: GatsbyNode["createPages"] = async ({ graphql, actions }) => {
  const { createPage } = actions

  const results = await graphql<
    AllMarkdownRemark<{
      frontmatter: {
        slug: string
      }
    }>
  >(`
    {
      allMarkdownRemark {
        edges {
          node {
            frontmatter {
              slug
            }
          }
        }
      }
    }
  `)

  results.data?.allMarkdownRemark.edges.forEach(
    ({
      node: {
        frontmatter: { slug },
      },
    }) => {
      createPage({
        path: `/posts${slug}`,
        component: path.resolve("./src/components/PostLayout.tsx"),
        context: {
          slug,
        },
      })
    }
  )
}

exports.createPages = createPages

Context

In gatsby-node.ts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

...
	createPage({
        path: `/posts${slug}`,
        component: path.resolve("./src/components/PostLayout.tsx"),
        context: {
          slug, // here is context
        },
	})
	  ...

This field slug you can use in Creating a post page in GatsbyJS > Page Query as the parameter of the query:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export const query = graphql`
  query BlogPostQuery($slug: String!) { // here is the field from context
    markdownRemark(frontmatter: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
        date
      }
    }
  }
`

Syntax:

$slug: String!

  • $slug is the parameter name from context. it should be the same as in gatsby-node.ts
  • String is type of value
  • ! it means that the parameter is required

This parameter is needed to dynamically display the content with $slug = slug (where slug is coming from url “localhost/posts/{slug}”) in PostLayout

Page Query

In the component PostLayout put GraphQL query:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export const query = graphql`
  query BlogPost {
    markdownRemark(frontmatter: { slug: { eq: "/greetings-post" } }) {
      html
      frontmatter {
        title
        date
      }
    }
  }
`

It should return data of the post with slug = “/greetings-post” and put it into ⚠️ props of the component:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

type Props {
  data: {
    markdownRemark: {
      html: string;
      frontmatter: {
        title: string;
        date: string;
      }
    }
  }
}

const PostLayout = ({data}: Props) => {
  return (
    <Layout>
      <h1>Some Post</h1>
    </Layout>
  )
}

Display html in the post component

Using dangerouslySetInnerHTML

🚨 I don’t like this method of rendering html. Maybe there is some other solution.

1
2
3
4
5
6
7
8
9
const PostLayout = ({ data: { markdownRemark } }: PostLayoutProps) => {
	...
      <div
        dangerouslySetInnerHTML={{
          __html: markdownRemark.html,
        }}
      ></div>
	...
}