How to Create Infinite Scroll in React: Simple Guide
To create infinite scroll in React, use the
useEffect hook to add a scroll event listener that checks when the user nears the page bottom, then load more data by updating state. Combine this with useState to store items and a loading flag to prevent multiple fetches.Syntax
Infinite scroll in React typically uses these parts:
useStateto hold the list of items and loading status.useEffectto add and clean up the scroll event listener.- A scroll handler function that checks if the user scrolled near the bottom.
- A function to fetch or generate more items and update state.
javascript
import React, { useState, useEffect } from 'react'; function InfiniteScrollComponent() { const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); useEffect(() => { function handleScroll() { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100 && !loading) { loadMoreItems(); } } window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, [loading]); function loadMoreItems() { setLoading(true); // Fetch or generate more items here setTimeout(() => { setItems(prev => [...prev, ...Array.from({ length: 10 }, (_, i) => prev.length + i + 1)]); setLoading(false); }, 1000); } return null; // UI omitted for brevity } export default InfiniteScrollComponent;
Example
This example shows a list that loads 10 more numbers each time you scroll near the bottom. It uses React hooks to manage state and scroll events.
javascript
import React, { useState, useEffect } from 'react'; export default function InfiniteScrollExample() { const [items, setItems] = useState(Array.from({ length: 20 }, (_, i) => i + 1)); const [loading, setLoading] = useState(false); useEffect(() => { function onScroll() { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 50 && !loading) { loadMore(); } } window.addEventListener('scroll', onScroll); return () => window.removeEventListener('scroll', onScroll); }, [loading]); function loadMore() { setLoading(true); setTimeout(() => { setItems(prev => [...prev, ...Array.from({ length: 10 }, (_, i) => prev.length + i + 1)]); setLoading(false); }, 1000); } return ( <main style={{ maxWidth: '400px', margin: 'auto', padding: '1rem' }}> <h2>Infinite Scroll List</h2> <ul> {items.map(item => ( <li key={item} style={{ padding: '0.5rem 0', borderBottom: '1px solid #ccc' }}> Item {item} </li> ))} </ul> {loading && <p>Loading more items...</p>} </main> ); }
Output
A scrollable list showing items numbered 1 to 20 initially. When you scroll near the bottom, it loads 10 more items each time, showing a "Loading more items..." message briefly.
Common Pitfalls
Common mistakes when creating infinite scroll in React include:
- Not cleaning up the scroll event listener, causing memory leaks.
- Triggering multiple loads at once by not checking a loading flag.
- Using fixed scroll positions without considering dynamic content height.
- Not throttling or debouncing scroll events, leading to performance issues.
Always remove event listeners in useEffect cleanup and use a loading state to prevent repeated fetches.
javascript
/* Wrong: No cleanup and no loading check */ useEffect(() => { window.addEventListener('scroll', () => { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) { loadMoreItems(); } }); }, []); /* Right: Cleanup and loading check */ useEffect(() => { function onScroll() { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100 && !loading) { loadMoreItems(); } } window.addEventListener('scroll', onScroll); return () => window.removeEventListener('scroll', onScroll); }, [loading]);
Quick Reference
- useState: Store items and loading state.
- useEffect: Add and remove scroll listener.
- Scroll handler: Detect near-bottom scroll.
- Loading flag: Prevent multiple fetches.
- Cleanup: Remove event listener on unmount.
Key Takeaways
Use
useEffect to add and clean up scroll event listeners properly.Check scroll position and a loading flag before fetching more data.
Update state with new items to trigger re-render and show more content.
Avoid multiple simultaneous loads by managing a loading state.
Clean up event listeners to prevent memory leaks and bugs.