load more feature in react node mern stack

Add load more posts feature. For testing purpose we will load only 3 posts at first load. Then each time Load More button is clicked, we fetch additional posts and render.

// route
router.get("/posts/:page", posts);
// controller updated
export const posts = async (req, res) => {
  try {
    const perPage = 3;
    const page = req.params.page ? req.params.page : 1;

    const posts = await Post.find({})
      .skip((page - 1) * perPage)
      .populate("postedBy", "_id name")
      .populate("categories", "_id name slug")
      .populate("featuredImage", "url")
      .sort({ createdAt: -1 })
      .limit(perPage)
      .exec();
    return res.json(posts);
  } catch (err) {
    console.log(err);
  }
};

Posts page

import { useEffect, useState } from "react";
import axios from "axios";
import { Card, Row, Col, Avatar, Button } from "antd";
import Head from "next/head";
import Link from "next/link";

const { Meta } = Card;

const Posts = ({ posts }) => {
  const [allPosts, setAllPosts] = useState(posts);
  const [total, setTotal] = useState(0);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    getTotal();
  }, []);

  useEffect(() => {
    if (page === 1) return;
    loadMore();
  }, [page]);

  const getTotal = async () => {
    try {
      const { data } = await axios.get("/post-count");
      setTotal(data);
    } catch (err) {
      console.log(err);
    }
  };

  const loadMore = async () => {
    try {
      setLoading(true);
      const { data } = await axios.get(`/posts/${page}`);
      setAllPosts([...allPosts, ...data]);
      setLoading(false);
    } catch (err) {
      setLoading(false);
      console.log(err);
    }
  };

  return (
    <>
      <Head>
        <title>Recent blog posts</title>
        <meta
          name="description"
          content="Blog posts about web development, programming, and more."
        />
      </Head>
      <div style={{ marginTop: "60px" }}></div>
      <Row gutter={12}>
        {allPosts.map((post) => (
          <Col xs={24} xl={8} style={{ marginBottom: 12 }}>
            <Link href={`/post/${post.slug}`}>
              <a>
                <Card
                  hoverable
                  cover={
                    <Avatar
                      shape="square"
                      style={{ height: "200px" }}
                      src={
                        post.featuredImage?.url ||
                        "https://via.placeholder.com/1200x800.png?text=..."
                      }
                      alt={post.title}
                    />
                  }
                >
                  <Meta title={post.title} />
                </Card>
              </a>
            </Link>
          </Col>
        ))}
      </Row>

      <Row>
        <Col span={24} style={{ textAlign: "center" }}>
          {allPosts?.length < total && (
            <div style={{ padding: 50 }}>
              <Button
                size="large"
                type="primary"
                loading={loading}
                onClick={() => setPage(page + 1)}
              >
                Load More
              </Button>
            </div>
          )}
        </Col>
      </Row>
    </>
  );
};

export async function getServerSideProps() {
  const { data } = await axios.get(`${process.env.API}/posts/1`);
  // console.log("DATA =====> ", data.length);
  return {
    props: {
      posts: data,
    },
  };
}

export default Posts;