Infinite scroll component for React that supports both window and element-based scrolling with customizable thresholds and reverse mode.
npx @tessl/cli install tessl/npm-react-infinite-scroller@1.2.00
# React Infinite Scroller
1
2
React Infinite Scroller is a lightweight React component that provides infinite scrolling functionality for both window and element-based scroll detection. It supports customizable thresholds, reverse scrolling for chat-like interfaces, and passive event listeners for optimal performance.
3
4
## Package Information
5
6
- **Package Name**: react-infinite-scroller
7
- **Package Type**: npm
8
- **Language**: JavaScript (React component)
9
- **Installation**: `npm install react-infinite-scroller`
10
11
## Core Imports
12
13
```javascript
14
import InfiniteScroll from 'react-infinite-scroller';
15
```
16
17
For CommonJS:
18
19
```javascript
20
const InfiniteScroll = require('react-infinite-scroller');
21
```
22
23
## Basic Usage
24
25
```javascript
26
import React, { useState } from 'react';
27
import InfiniteScroll from 'react-infinite-scroller';
28
29
function MyComponent() {
30
const [items, setItems] = useState([]);
31
const [hasMore, setHasMore] = useState(true);
32
33
const loadMore = async (page) => {
34
try {
35
// Note: page starts from pageStart + 1 (so if pageStart=0, first call gets page=1)
36
const response = await fetch(`/api/items?page=${page}`);
37
const newItems = await response.json();
38
39
if (newItems.length === 0) {
40
setHasMore(false);
41
} else {
42
setItems(prevItems => [...prevItems, ...newItems]);
43
}
44
} catch (error) {
45
console.error('Failed to load items:', error);
46
}
47
};
48
49
return (
50
<InfiniteScroll
51
pageStart={0}
52
loadMore={loadMore}
53
hasMore={hasMore}
54
loader={<div className="loader" key={0}>Loading...</div>}
55
>
56
<div>
57
{items.map((item, index) => (
58
<div key={index}>{item.name}</div>
59
))}
60
</div>
61
</InfiniteScroll>
62
);
63
}
64
```
65
66
## Capabilities
67
68
### InfiniteScroll Component
69
70
Core React component that handles infinite scroll functionality with comprehensive configuration options.
71
72
```javascript { .api }
73
/**
74
* React component for infinite scrolling functionality
75
* @component
76
*/
77
function InfiniteScroll(props: InfiniteScrollProps): React.ReactElement;
78
79
interface InfiniteScrollProps {
80
/** Content to be rendered inside the scroll container (required) */
81
children: React.ReactNode;
82
83
/** Callback function triggered when more content needs to be loaded (required)
84
* @param page - Page number starting from pageStart + 1 */
85
loadMore: (page: number) => void;
86
87
/** HTML element type to render as container */
88
element?: string | React.ComponentType;
89
90
/** Whether more items are available to load
91
* When false, all scroll event listeners are automatically removed */
92
hasMore?: boolean;
93
94
/** Whether to trigger loadMore on component mount */
95
initialLoad?: boolean;
96
97
/** Whether to load content when scrolling to top (chat-like behavior) */
98
isReverse?: boolean;
99
100
/** React element to display while loading */
101
loader?: React.ReactNode;
102
103
/** Starting page number for loadMore callback */
104
pageStart?: number;
105
106
/** Ref callback to access the scroll container element
107
* Note: Called after internal ref processing for scroll detection */
108
ref?: (node: HTMLElement | null) => void;
109
110
/** Function to override default scroll parent detection */
111
getScrollParent?: () => HTMLElement;
112
113
/** Distance in pixels from scroll end to trigger loadMore */
114
threshold?: number;
115
116
/** Event listener capture option */
117
useCapture?: boolean;
118
119
/** Whether to use window scroll events or parent element events */
120
useWindow?: boolean;
121
}
122
```
123
124
**Default Props:**
125
- `element`: `'div'`
126
- `hasMore`: `false`
127
- `initialLoad`: `true`
128
- `pageStart`: `0`
129
- `ref`: `null`
130
- `threshold`: `250`
131
- `useWindow`: `true`
132
- `isReverse`: `false`
133
- `useCapture`: `false`
134
- `loader`: `null`
135
- `getScrollParent`: `null`
136
137
### Window Scroll Mode
138
139
Default behavior using window scroll events for infinite scrolling.
140
141
```javascript
142
<InfiniteScroll
143
pageStart={0}
144
loadMore={loadFunc}
145
hasMore={true}
146
loader={<div className="loader" key={0}>Loading...</div>}
147
>
148
{items}
149
</InfiniteScroll>
150
```
151
152
### Element Scroll Mode
153
154
Infinite scrolling within a specific scrollable container element.
155
156
```javascript
157
<div style={{height: '400px', overflow: 'auto'}}>
158
<InfiniteScroll
159
pageStart={0}
160
loadMore={loadFunc}
161
hasMore={true}
162
loader={<div className="loader" key={0}>Loading...</div>}
163
useWindow={false}
164
>
165
{items}
166
</InfiniteScroll>
167
</div>
168
```
169
170
### Custom Parent Element
171
172
Using a custom parent element for scroll calculations with getScrollParent.
173
174
```javascript
175
function MyComponent() {
176
const scrollParentRef = useRef(null);
177
178
return (
179
<div
180
style={{height: '400px', overflow: 'auto'}}
181
ref={scrollParentRef}
182
>
183
<div>
184
<InfiniteScroll
185
pageStart={0}
186
loadMore={loadFunc}
187
hasMore={true}
188
loader={<div className="loader" key={0}>Loading...</div>}
189
useWindow={false}
190
getScrollParent={() => scrollParentRef.current}
191
>
192
{items}
193
</InfiniteScroll>
194
</div>
195
</div>
196
);
197
}
198
```
199
200
### Reverse Scrolling (Chat Mode)
201
202
Loading content when scrolling to the top, useful for chat interfaces.
203
204
```javascript
205
<InfiniteScroll
206
pageStart={0}
207
loadMore={loadFunc}
208
hasMore={true}
209
loader={<div className="loader" key={0}>Loading...</div>}
210
isReverse={true}
211
>
212
{messages}
213
</InfiniteScroll>
214
```
215
216
### Instance Methods
217
218
#### setDefaultLoader
219
220
Sets a default loader component for all InfiniteScroll instances.
221
222
```javascript { .api }
223
/**
224
* Set a default loader for all InfiniteScroll components
225
* @param loader - React element to use as default loader
226
*/
227
setDefaultLoader(loader: React.ReactNode): void;
228
```
229
230
**Usage:**
231
```javascript
232
const infiniteScrollRef = useRef(null);
233
234
// Set default loader on component instance
235
useEffect(() => {
236
if (infiniteScrollRef.current) {
237
infiniteScrollRef.current.setDefaultLoader(
238
<div className="default-loader">Loading more items...</div>
239
);
240
}
241
}, []);
242
243
return (
244
<InfiniteScroll
245
ref={infiniteScrollRef}
246
pageStart={0}
247
loadMore={loadFunc}
248
hasMore={true}
249
>
250
{items}
251
</InfiniteScroll>
252
);
253
```
254
255
## Event Handling and Performance
256
257
The component automatically handles:
258
- **Passive event listeners**: Uses passive listeners when supported for better performance
259
- **Event cleanup**: Removes all event listeners on component unmount and when `hasMore` becomes false
260
- **Chrome optimization**: Prevents Chrome hangups with specific mousewheel handling
261
- **Scroll position management**: Maintains scroll position in reverse mode after new content loads
262
- **Page numbering**: The `loadMore` callback receives page numbers starting from `pageStart + 1`
263
264
## Common Patterns
265
266
### Loading State Management
267
268
```javascript
269
function InfiniteList() {
270
const [items, setItems] = useState([]);
271
const [hasMore, setHasMore] = useState(true);
272
const [isLoading, setIsLoading] = useState(false);
273
274
const loadMore = async (page) => {
275
if (isLoading) return; // Prevent overlapping requests
276
277
setIsLoading(true);
278
try {
279
const newItems = await fetchItems(page);
280
if (newItems.length === 0) {
281
setHasMore(false);
282
} else {
283
setItems(prev => [...prev, ...newItems]);
284
}
285
} finally {
286
setIsLoading(false);
287
}
288
};
289
290
return (
291
<InfiniteScroll
292
pageStart={0}
293
loadMore={loadMore}
294
hasMore={hasMore && !isLoading}
295
loader={<div>Loading...</div>}
296
>
297
<div>
298
{items.map((item, index) => (
299
<div key={item.id || index}>{item.content}</div>
300
))}
301
</div>
302
</InfiniteScroll>
303
);
304
}
305
```
306
307
### Custom Threshold
308
309
```javascript
310
<InfiniteScroll
311
pageStart={0}
312
loadMore={loadFunc}
313
hasMore={true}
314
threshold={100} // Trigger load when 100px from bottom
315
loader={<div>Loading...</div>}
316
>
317
{items}
318
</InfiniteScroll>
319
```
320
321
### Error Handling
322
323
```javascript
324
const loadMore = async (page) => {
325
try {
326
const newItems = await fetchItems(page);
327
setItems(prev => [...prev, ...newItems]);
328
setHasMore(newItems.length > 0);
329
} catch (error) {
330
console.error('Failed to load items:', error);
331
setHasMore(false); // Stop further loading attempts
332
}
333
};
334
```