Created
April 4, 2025 00:30
-
-
Save msell/5c441dbe19f016bbad0bacb38f6316df to your computer and use it in GitHub Desktop.
Infinite scroll hook pattern (https://stackblitz.com/edit/vitejs-vite-mavgegks?file=src%2FApp.tsx)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import './App.css'; | |
import useInfiniteScroll from './useInfiniteScroll'; | |
import { useState, useEffect } from 'react'; | |
const PAGE_SIZE = 10; | |
const fetchPosts = async (page: number) => { | |
const response = await fetch( | |
`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${PAGE_SIZE}` | |
); | |
return response.json(); | |
}; | |
function App() { | |
const [posts, setPosts] = useState<any[]>([]); | |
const [page, setPage] = useState(1); | |
const [hasMore, setHasMore] = useState(true); | |
const [loading, setLoading] = useState(false); | |
const loadMore = async () => { | |
if (loading) return; | |
setLoading(true); | |
const newPosts = await fetchPosts(page); | |
setPosts((prev) => [...prev, ...newPosts]); | |
setPage((prev) => prev + 1); | |
setLoading(false); | |
// JSONPlaceholder only has 100 posts, so stop after page 10 | |
if (page >= 10) setHasMore(false); | |
}; | |
const lastItemRef = useInfiniteScroll(loadMore, hasMore); | |
useEffect(() => { | |
loadMore(); // Fetch initial data | |
}, []); | |
return ( | |
<div> | |
<h2>Infinite Scroll with JSONPlaceholder</h2> | |
{posts.map((post, index) => ( | |
<div | |
key={crypto.randomUUID()} | |
ref={index === posts.length - 1 ? lastItemRef : null} | |
style={{ padding: 10, border: '1px solid black', marginBottom: 5 }} | |
> | |
<h4>{post.title}</h4> | |
<p>{post.body}</p> | |
</div> | |
))} | |
{loading && <p>Loading more posts...</p>} | |
{!hasMore && <p>No more posts available</p>} | |
</div> | |
); | |
} | |
export default App; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import './App.css'; | |
import useInfiniteScroll from './useInfiniteScroll'; | |
import { useState, useEffect } from 'react'; | |
const PAGE_SIZE = 10; | |
const fetchPosts = async (page: number) => { | |
const response = await fetch( | |
`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${PAGE_SIZE}` | |
); | |
return response.json(); | |
}; | |
function App() { | |
const [posts, setPosts] = useState<any[]>([]); | |
const [page, setPage] = useState(1); | |
const [hasMore, setHasMore] = useState(true); | |
const [loading, setLoading] = useState(false); | |
const loadMore = async () => { | |
if (loading) return; | |
setLoading(true); | |
const newPosts = await fetchPosts(page); | |
setPosts((prev) => [...prev, ...newPosts]); | |
setPage((prev) => prev + 1); | |
setLoading(false); | |
// JSONPlaceholder only has 100 posts, so stop after page 10 | |
if (page >= 10) setHasMore(false); | |
}; | |
const lastItemRef = useInfiniteScroll(loadMore, hasMore); | |
useEffect(() => { | |
loadMore(); // Fetch initial data | |
}, []); | |
return ( | |
<div> | |
<h2>Infinite Scroll with JSONPlaceholder</h2> | |
{posts.map((post, index) => ( | |
<div | |
key={crypto.randomUUID()} | |
ref={index === posts.length - 1 ? lastItemRef : null} | |
style={{ padding: 10, border: '1px solid black', marginBottom: 5 }} | |
> | |
<h4>{post.title}</h4> | |
<p>{post.body}</p> | |
</div> | |
))} | |
{loading && <p>Loading more posts...</p>} | |
{!hasMore && <p>No more posts available</p>} | |
</div> | |
); | |
} | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment