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…
  • Create a file called posts.js inside with the following contents:
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
    }
  })
}

And in pages/index.js, import this function:

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

Then call this function in getStaticProps. You need to return the result inside the props key:

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

Once this is set up, the allPostsData prop will be passed to the Home component. To see this, modify the component definition to take { allPostsData }:

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

To display the data, add another <section> tag at the bottom of this component:

export default function Home({ allPostsData }) {
  return (
    <Layout home>
      <Head></Head>
      <section className={utilStyles.headingMd}></section>
      <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.