Pre-rendering and Data Fetching

Implement getStaticProps

First, install gray-matter which lets us parse the metadata in each markdown file.

npm install gray-matter

Next, we’ll create a simple library for fetching data from the file system.

  • Create a top-level directory called lib, and…
  • Inside lib, create a file called posts.js with the following content:
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'

const postsDirectory = path.join(process.cwd(), 'posts')

export function getSortedPostsData() {
  // Get file names under /posts
  const fileNames = fs.readdirSync(postsDirectory)
  const allPostsData = fileNames.map(fileName => {
    // Remove ".md" from file name to get id
    const id = fileName.replace(/\.md$/, '')

    // Read markdown file as string
    const fullPath = path.join(postsDirectory, fileName)
    const fileContents = fs.readFileSync(fullPath, 'utf8')

    // Use gray-matter to parse the post metadata section
    const matterResult = matter(fileContents)

    // Combine the data with the id
    return {
      id,
      ...matterResult.data
    }
  })
  // Sort posts by date
  return allPostsData.sort((a, b) => {
    if (a.date < b.date) {
      return 1
    } else {
      return -1
    }
  })
}

Now, we need to add an import for getSortedPostsData and call it inside getStaticProps in pages/index.js.

Open pages/index.js in your editor and add the following code above the exported Home component:

import { getSortedPostsData } from '../lib/posts'

export async function getStaticProps() {
  const allPostsData = getSortedPostsData()
  return {
    props: {
      allPostsData
    }
  }
}

By returning allPostsData inside the props object in getStaticProps, the blog posts will be passed to the Home component as a prop. Now you can access the blog posts like so:

export default function Home ({ allPostsData }) { ... }

To display the blog posts, let's update the Home component to add another <section> tag with the data below the section with your self introduction. Don't forget to also change the props from () to ({ allPostsData }):

export default function Home({ allPostsData }) {
  return (
    <Layout home>
      {/* Keep the existing code here */}

      {/* Add this <section> tag below the existing <section> tag */}
      <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
        <h2 className={utilStyles.headingLg}>Blog</h2>
        <ul className={utilStyles.list}>
          {allPostsData.map(({ id, date, title }) => (
            <li className={utilStyles.listItem} key={id}>
              {title}
              <br />
              {id}
              <br />
              {date}
            </li>
          ))}
        </ul>
      </section>
    </Layout>
  )
}

You should now see the blog data if you access http://localhost:3000.

Congratulations! We’ve successfully fetched external data (from the file system) and pre-rendered the index page with this data.

Let’s talk about some tips for using getStaticProps on the next page.