👋 Next.js Conf 2024: Come build, party, run, and connect with us! See all events

How to add a Load More button to a Sanity blog list

4 replies
Last updated: Jun 3, 2023
Hello, Everyone.
Please tell me how to connect together in different ways. Take the code from the first variant with Load Mode button and add it to the code of Sanity Posts ?

#1 - Load More

'use client'

import { useEffect, useState } from "react"


export default function Page() {
  const [items, setItems] = useState([]);
  const [visible, setVisible] = useState(24)

  const showMoreItems = () => {
    setVisible((prevValue) => prevValue + 24)
  }

  useEffect(() => {
    fetch("<https://jsonplaceholder.typicode.com/posts>")
    .then((res) => res.json())
    .then((data) => setItems(data))
  }, [])

  return (
    <div className='container py-4'>
      <div className="grid sm:grid-cols-2 gap-4">
      {items.slice(0, visible).map((item: any) =>(
        <div key={item.id} className="p-4 border rounded-lg space-y-2">
          <h2 className="tetx-xl font-bold">{item.title}</h2>
          <p>{item.body}</p>
        </div>
      ))}
      </div>

      <button className="py-3 w-full bg-blue-600 text-white mt-4 rounded-lg" onClick={showMoreItems}>Load More</button>
    </div>
  )
}
#2 - Sanity


import { getPostsApps } from "@/sanity-utils"
import Image from 'next/image'
import Link from 'next/link'

export default async function Apps() {
  const posts = await getPostsApps();

  return (
    <main className="container py-12">
      <div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 3xl:grid-cols-4 gap-12 2xl:gap-16'>
        {posts.map((post) => {
          return (
            <div key={post._id} className='space-y-4'>
              <Link
                href={post.url}
                target='_blank'
                title={post.name}
                rel="noopener noreferrer inline-block"
              >
                <div className="relative">
                  <Image
                    src={post.image}
                    alt={post.name}
                    width={460}
                    height={320}
                    className={post.border ? "object-cover rounded-lg w-full border border-slate-200" : "object-cover rounded-lg w-full"}
                  />
      
                  {post.new && <div className="absolute right-2 top-2 z-10 bg-blue-600 text-white text-xs py-0.5 px-1.5 rounded">New</div>}
                </div>
              </Link>

              <h2 className='text-2xl md:text-3xl font-bold leading-tight text-default'>{post.name}</h2>
              <p className='md:text-lg leading-relaxed font-light text-default'>{post.content}</p>
            </div>
          );
        })}
      </div>
    </main>
  )
}
[0...24] -
Sanity.io ’s documentation doesn’t tell you how to download the rest of the posts.
export async function getPosts(): Promise<Posts[]> {
  return client.fetch(
    groq`*[_type == "posts"] | order(_createdAt desc) [0...24] { //&& favorites
      _id,
      new,
      name,
      url,
      "image": image.asset->url,
      "alt": image.alt,
      border,
      content,
      category->,
      author->,
    }`
  )
}
Jun 2, 2023, 6:07 PM
If you search the docs , you’ll find a couple of examples for paginating your results.
Jun 2, 2023, 7:36 PM
Thank you. Unfortunately, that’s not it at all. I know how to make a limit on the number of posts in Sanity. In the documentation there is not a single example of how to make a button load more, not just theory, namely an example of code page posts.tsx. The video tutorials also show how to make a blog, but how to make dynamic pagination I have not found.
If possible, please make an example of how to connect my two options above. I think it will be very useful not only for me. Because all the examples or ready-made assemblies on the site are not full-fledged solutions for a blog.
Jun 3, 2023, 8:49 AM
Hi
user J
, under the guides section on the Sanity site is a example. Here the link:

https://hdoro.dev/minimal-sanity-io-pagination
Jun 3, 2023, 1:07 PM
Hi
user J
, Unfortunately, it didn’t help me. But I managed to find a solution. This is exactly the solution I was looking for. There are no concrete examples in the documentation. Mostly theory. I’m still new to Sanity and it’s hard to apply solutions from the documentation.

./app/page.tsx

import { getPostsApps } from "@/sanity-utils"
import BlogList from "@/components/BlogList";

export default async function Apps() {
  const posts = await getPostsApps();

  return (
    <main className="container py-12">

      <div className="text-center mb-12 md:mb-16">
        <h1 className="text-2xl xs:text-5xl font-black text-default">
          Category: APPS
        </h1>
      </div>

      <div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 3xl:grid-cols-4 gap-12 2xl:gap-16'>
        <BlogList posts={posts} />  
      </div>
    </main>
  )
}

./components/BlogList.tsx

"use client"

import { useState } from "react"

import Image from 'next/image'
import Link from 'next/link'

type Props = {
  posts: Posts[];
};

const BlogList = ({ posts }: Props) => {

  const articlesShown = 4;
  const [loadMore, setLoadMore] = useState(articlesShown);
  const showMoreArticles = () => {
    setLoadMore(loadMore + articlesShown);
  };

  return (
      <div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 3xl:grid-cols-4 gap-12 2xl:gap-16'>
        {posts.slice(0, loadMore).map((post) => {
          return (
            <div key={post._id} className='space-y-4'>
              <Link
                href={post.url}
                target='_blank'
                title={post.name}
                rel="noopener noreferrer inline-block"
              >
                <div className="relative">
                  <Image
                    src={post.image}
                    alt={post.name}
                    width={460}
                    height={320}
                    className={post.border ? "object-cover rounded-lg w-full border border-slate-200" : "object-cover rounded-lg w-full"}
                  />
      
                  {post.new && <div className="absolute right-2 top-2 z-10 bg-blue-600 text-white text-xs py-0.5 px-1.5 rounded">New</div>}
                </div>
              </Link>
              
              {/* <h3 className="text-xs font-bold uppercase text-default">
                {post.category.name}
               </h3> */}

              <h2 className='text-2xl md:text-3xl font-bold leading-tight text-default'>{post.name}</h2>
              <p className='md:text-lg leading-relaxed font-light text-default'>{post.content}</p>
            </div>
          );
        })}

        <div className="flex justify-center">
          {loadMore < posts?.length ? (
            <button
              type="button"
              className="group relative overflow-hidden bg-white px-2 py-3 text-sm md:text-base rounded-lg"
              onClick={showMoreArticles}
            >
              <div className="absolute inset-0 w-3  bg-[#8F00FF]  transition-all duration-[350ms] ease-out group-hover:w-full"></div>
              <span className="relative text-black group-hover:text-white ">
                Load More Articles
              </span>
            </button>
          ) : (
            <button
              type="button"
              className="bg-[#483248] text-[#FFF] px-2 py-3 text-sm md:text-base rounded-lg opacity-50 cursor-not-allowed"
              onClick={showMoreArticles}
              disabled
            >
              All articles loaded
            </button>
          )}
        </div>
        <div className="flex justify-center mt-5">
          Showing {loadMore} of {posts?.length} articles
        </div>
      </div>
      
  )
}
export default BlogList;
Jun 3, 2023, 2:20 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?