Creating a generic posts function - part 14

dailydevtips1

Chris Bongers

Posted on October 21, 2022

Creating a generic posts function - part 14

For this article, I want to add the latest two blog posts to our homepage. However, it quickly made me realize we are reusing the same code repeatedly.

So let's start this article by re-doing some of the code so we can reuse it in existing components.

Before we start, we'll identify the different calls we currently have:

  • A function that retrieves all posts
  • A function that retrieves a single post by slug

And for the homepage, we want to retrieve all posts sorted by date and render two of them.

Creating a shared function

Create a new folder called lib inside your root directory.
Add a file called api.js which will serve as our API.

We can start by adding the call for all posts.
We have this function already in our blog post overview, so modify and copy that one.

import fs from 'fs';
import matter from 'gray-matter';

export function getAllPosts() {
  const files = fs.readdirSync('./posts');
  const posts = files
    .map((fileName) => {
      const slug = fileName.replace('.md', '');
      const readFile = fs.readFileSync(`posts/${fileName}`, 'utf-8');
      const { data: frontmatter } = matter(readFile);
      return {
        slug,
        ...frontmatter,
      };
    })
    .sort((post1, post2) => (post1.date > post2.date ? -1 : 1));

  return posts;
}
Enter fullscreen mode Exit fullscreen mode

The only thing I added is a sort based on the date.
This way, we always show the newest articles first.

As mentioned, the rest is a copy-paste from what we already had.

Now let's also create the getPostBySlug function, which we can copy from our [slug] page again.

export function getPostBySlug(slug) {
  const fileName = fs.readFileSync(`posts/${slug}.md`, 'utf-8');
  const { data: frontmatter, content } = matter(fileName);
  return {
    frontmatter,
    content,
  };
}
Enter fullscreen mode Exit fullscreen mode

For the people paying attention, you'll see this function duplicates what we had inside the all-post function.

Let's refactor that one so it uses this now.

export function getAllPosts() {
  const files = fs.readdirSync('./posts');
  const posts = files
    .map((fileName) => {
      const slug = fileName.replace('.md', '');
      const { frontmatter } = getPostBySlug(slug);
      return {
        slug,
        ...frontmatter,
      };
    })
    .sort((post1, post2) => (post1.date > post2.date ? -1 : 1));

  return posts;
}
Enter fullscreen mode Exit fullscreen mode

Way cleaner!

Using the new API calls

Now that our API calls are ready, let's adjust our pages so they use this.

The first one is the pages/blog/index.js file.

import { getAllPosts } from '../../lib/api';

export async function getStaticProps() {
  const posts = getAllPosts();

  return {
    props: {
      posts,
    },
  };
}
Enter fullscreen mode Exit fullscreen mode

Yep, it's as simple as that!
The benefit, of course, is that if we ever change something in our post call, it's reflected everywhere that uses it.

The next file we need to change is the pages/blog/[slug].js file.
This will use both function as they will look like this:

import { getAllPosts, getPostBySlug } from '../../lib/api';

export async function getStaticPaths() {
  const posts = getAllPosts();

  return {
    paths: posts.map((post) => {
      return {
        params: {
          slug: post.slug,
        },
      };
    }),
    fallback: false,
  };
}

export async function getStaticProps({ params: { slug } }) {
  const post = getPostBySlug(slug);
  return {
    props: post,
  };
}
Enter fullscreen mode Exit fullscreen mode

And yep, that's all. Our system is now back to working as intended.

Adding the latest post to the homepage.

Let's come back to the initial idea for this article.
We wanted to add the latest two articles on the homepage, so how can we do this now?

Open up the pages/index.js file and add a staticProps function.

import { getAllPosts } from '../lib/api';

export async function getStaticProps() {
  const posts = getAllPosts();

  return {
    props: {
      posts,
    },
  };
}
Enter fullscreen mode Exit fullscreen mode

This will ensure we have access to our post data.
Inside the component, we can retrieve this posts variable and, in return, pass it to our recent posts component.

export default function Home({ posts }) {
  return (
    <div>
      <Head>
        <title>NextJS Portfolio</title>
        <meta name='description' content='Generated by create next app' />
        <link rel='icon' href='/favicon.ico' />
      </Head>
      <IntroHeader />
      <RecentPosts posts={posts} />
      <FeaturedWork />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Let's go to the recent posts component and ensure we know what to do with this data.

import SectionHeader from './sectionHeader';
import Article from './article';

export default function RecentPosts({ posts }) {
  return (
    <section className='bg-blue-100 px-6'>
      <div className='max-w-4xl mx-auto py-12'>
        <SectionHeader title='Recent posts' href='#' />
        <div className='grid grid-cols-1 md:grid-cols-2 gap-6'>
          <Article post={posts[0]} />
          <Article post={posts[1]} />
        </div>
      </div>
    </section>
  );
}
Enter fullscreen mode Exit fullscreen mode

And yep, that's it!

Homepage latest posts

Our homepage now shows the latest two articles, and we didn't have to recreate existing code for it.

You can also find the completed code for today on GitHub.

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

💖 💪 🙅 🚩
dailydevtips1
Chris Bongers

Posted on October 21, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Optimizing the PageSpeed results - part 17
javascript Optimizing the PageSpeed results - part 17

October 24, 2022

Making the site responsive - part 11
javascript Making the site responsive - part 11

October 18, 2022

Making the menu work - part 10
javascript Making the menu work - part 10

October 17, 2022