Skip to content

zainali954/infinite-scroll-tanstack-query

Repository files navigation

📄 Infinite Scroll with TanStack Query

A reusable infinite scrolling component built using React, TanStack Query, and Tailwind CSS, with posts fetched from JSONPlaceholder.


🚀 Features

  • Reusable custom hook: useInfinitePosts
  • Auto-loads next posts when scrolling to the bottom
  • Uses Intersection Observer under the hood
  • Fully responsive & styled with Tailwind CSS

📦 Dependencies

npm install @tanstack/react-query
npm install tailwindcss @tailwindcss/vite

Also make sure Tailwind is properly configured. You can use Tailwind CLI guide or Vite setup.


🧩 Folder Structure

src/
├── api/
│   └── posts.js                // API logic
├── hooks/
│   └── useInfinitePosts.js     // Infinite query logic
├── components/
│   └── InfiniteScroll/
│       └── InfiniteScroll.jsx  // UI logic
├── App.jsx
└── main.jsx

🛠️ Steps to Build

  1. Set up TanStack Query Provider in main.jsx:

    import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
    
    const queryClient = new QueryClient();
    
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  2. Create the fetcher function in api/posts.js:

     import axios from "axios"
     
     export const fetchPosts = async ({pageParam=1})=>{
         const response = await axios.get(`https://jsonplaceholder.typicode.com/posts?_limit=10&_page=${pageParam}`)
         return response.data
     }
  3. Create the custom hook in hooks/useInfinitePosts.js:

    import { useInfiniteQuery } from "@tanstack/react-query";
    import { fetchPosts } from "../api/posts";
    
    export function useInfinitePosts() {
      return useInfiniteQuery({
        queryKey: ["posts"],
        queryFn: fetchPosts,
        getNextPageParam: (_lastPage, allPages) => allPages.length + 1,
      });
    }
  4. Build the component in components/InfiniteScroll/InfiniteScroll.jsx:

    import { useRef, useEffect } from "react";
    import { useInfinitePosts } from "../../hooks/useInfinitePosts";
    
    export default function InfiniteScroll() {
      const { data, fetchNextPage, hasNextPage, isFetchingNextPage, status, error } = useInfinitePosts();
      const loaderRef = useRef();
    
      useEffect(() => {
        const observer = new IntersectionObserver((entries) => {
          if (entries[0].isIntersecting && hasNextPage) {
            fetchNextPage();
          }
        });
        if (loaderRef.current) observer.observe(loaderRef.current);
        return () => observer.disconnect();
      }, [fetchNextPage, hasNextPage]);
    
      if (status === "loading") return <p>Loading...</p>;
      if (status === "error") return <p>Error: {error.message}</p>;
    
      return (
        <div className="space-y-4">
          {data.pages.map((group, i) => (
            <div key={i} className="space-y-2">
              {group.map((post) => (
                <div key={post.id} className="p-4 border rounded shadow">
                  <h2 className="font-semibold text-lg">{post.title}</h2>
                  <p className="text-sm text-gray-600">{post.body}</p>
                </div>
              ))}
            </div>
          ))}
          <div ref={loaderRef} className="h-10" />
          {isFetchingNextPage && <p>Loading more...</p>}
        </div>
      );
    }
  5. Use it inside App.jsx:

    import InfiniteScroll from "./components/InfiniteScroll/InfiniteScroll";
    
    function App() {
      return (
        <div className="max-w-2xl mx-auto p-4">
          <h1 className="text-3xl font-bold mb-6">Infinite Scroll</h1>
          <InfiniteScroll />
        </div>
      );
    }
    
    export default App;

✅ Result

An auto-loading infinite scroll for blog posts or feeds with a clean Tailwind layout and easy integration into any React app.

About

Infinite scroll implementation in React using TanStack Query and Intersection Observer.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published