How to add a "load more" button to your blog
Tags: nextjs, react, javascript, frontend
Published: 2023-03-06 10:26:20

Last week, I added some features to my blog. From the [preloader](https://meje.dev/blog/building-a-nextjs-preloader-the-right-way) that utilized Next.js' router API, to the search and [Table of Content component](https://meje.dev/blog/building-a-table-of-content-component).

Recently, I've just added a minor feature that allows me to conditionally render a certain amount of articles on my blog. Instead of having all the articles I've written all at once on the page.

This feature is a bit common on some developer blogging platforms., and building it was a bit straightforward since I knew what needs to be done. 

The idea behind it is for us to have an initial amount of articles listed whenever anyone navigates to the blog route. So, a variable like the one below should suffice

```js
const initialPostList = 6
```

And whenever a visitor clicks on the "load more" button, a callback function is triggered to increment the number of articles/posts on the blog. 

It'll be ideal to also have another variable that holds the increment value. A variable like the one below should work fine.

```js
const incrementInitialPostList = 4
```

## Watching the state

The snippets in the previous section are of great importance to this feature. `initialPostList` holds the amount of articles we want on initial render of the blog page, while `incrementInitialPostList` holds the value with which the articles list would be incremented.

With that said, some of the snippets here may look unfamiliar or intricate. If you happen to feel this way, when you're reading this, I'd implore you to check out this article that walks you through [how to build a Next.js blog](https://meje.dev/blog/how-i-built-this-blog)

I'm assuming you already have an idea of some Next.js data-fetching patterns, If not, please, take a look at the link I shared in the paragraph above.

I needed a way to keep these values &mdash; `initialPostList` and `incrementInitialPostList` &mdash; in the blog component's state, so that I can tap into its lifecycle methods .

The snippet below shows what the Blog component looks like.

```jsx
import Article from './Article'; // Replace with your own Article component

const initialPostList = 6; // Number of articles to display initially
const incrementInitialPostList = 4; // Number of articles to add each time the "load more" button is clicked

export default function Blog() {
  const [displayPosts, setDisplayPosts] = React.useState(initialPostList);
  const [articles, setArticles] = React.useState(/* Your array of articles goes here */);

  const loadMore = () => {
    setDisplayPosts(displayPosts + incrementInitialPostList)
  }

  return (
    <div>
      {articles.slice(0, displayPosts).map(article => (
        <Article key={article.id} article={article} />
      ))}
      {displayPosts < articles.length ? ( 
          <button onClick={handleLoadMore}>Load More</button>
      ) : null}
    </div>
  );
}
```

## Rendering more posts

In the snippet from the previous section, I'm using `initialPostList` variable to render the first 6 articles and adding the  `incrementInitialPostList` variable to represent the number of articles to render each time the "load more" button is clicked. 

The `loadMore` function simply updates the `displayPosts` state variable with the new value.

The articles array can come from any data source you like (e.g. an API endpoint, a static file, etc.), and you can customize the Article component to match the structure of your data.

But, in this case, it is coming from a markdown source, and I can get the list of articles with `getStaticProps`, a data-fetching method of Next.js

The blog component is modified like so;

```jsx
export default function Blog({ posts }) {
  const [displayPosts, setDisplayPosts] = React.useState(initialPostList);
  const [articles, setArticles] = React.useState(posts);

  const loadMore = () => {
    setDisplayPosts(displayPosts + incrementInitialPostList)
  }

  return (
    <div>
      {articles.slice(0, displayPosts).map(article => (
        <Article key={article.id} article={article} />
      ))}
      {displayPosts < articles.length ? ( 
          <button onClick={loadMore}>Load More</button>
      ) : null}
    </div>
  );
}

export async function getStaticProps() {
  let articles = await getAllArticles()

  const sortedArticles = articles.map((article) => article)

  sortedArticles.sort((a, b) => {
    return new Date(b.publishedAt) - new Date(a.publishedAt)
  })

  return {
    props: {
      posts: sortedArticles,
    },
  }
}
```

The slice function is used to only display the first item in the `posts` array through the value of the `displayPosts` value &mdash; which is 6 &mdash; from the articles array. 

The `displayPosts < articles.length` condition is used to check if there are more articles to display and show the "load more" button accordingly.

From @nlxdodge's comment below, I found an approach that helps you preserve the state when you navigate to, and away from the page. 

Take a look at it [here](https://meje.dev/blog/keep-state-in-the-url#a-real-life-example)