virtual-scroller 1.15.0 → 1.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +98 -8
- package/bundle/index-dom-bypass.html +3 -4
- package/bundle/index-dom-grid.html +3 -4
- package/bundle/index-dom-scrollableContainer.html +3 -4
- package/bundle/index-dom.html +3 -4
- package/bundle/index-react-bypass.html +56 -62
- package/bundle/index-react-grid.html +55 -61
- package/bundle/index-react-hook.html +209 -0
- package/bundle/index-react-scrollableContainer.html +56 -62
- package/bundle/index-react-strictMode.html +55 -61
- package/bundle/index-react-tbody-scrollableContainer.html +13 -15
- package/bundle/index-react-tbody.html +10 -12
- package/bundle/virtual-scroller-dom.js +1 -1
- package/bundle/virtual-scroller-dom.js.map +1 -1
- package/bundle/virtual-scroller-react.js +1 -1
- package/bundle/virtual-scroller-react.js.map +1 -1
- package/bundle/virtual-scroller.js +1 -1
- package/bundle/virtual-scroller.js.map +1 -1
- package/commonjs/react/VirtualScroller.js +69 -127
- package/commonjs/react/VirtualScroller.js.map +1 -1
- package/commonjs/react/useCreateVirtualScroller.js +64 -0
- package/commonjs/react/useCreateVirtualScroller.js.map +1 -0
- package/commonjs/react/useInstanceMethods.js +2 -2
- package/commonjs/react/useInstanceMethods.js.map +1 -1
- package/commonjs/react/useMergeRefs.js +52 -0
- package/commonjs/react/useMergeRefs.js.map +1 -0
- package/commonjs/react/{useVirtualScrollerStartStop.js → useStartStopVirtualScroller.js} +1 -1
- package/commonjs/react/{useVirtualScrollerStartStop.js.map → useStartStopVirtualScroller.js.map} +1 -1
- package/commonjs/react/useStyle.js +18 -0
- package/commonjs/react/useStyle.js.map +1 -1
- package/commonjs/react/useVirtualScroller.js +142 -43
- package/commonjs/react/useVirtualScroller.js.map +1 -1
- package/modules/react/VirtualScroller.js +68 -119
- package/modules/react/VirtualScroller.js.map +1 -1
- package/modules/react/useCreateVirtualScroller.js +53 -0
- package/modules/react/useCreateVirtualScroller.js.map +1 -0
- package/modules/react/useInstanceMethods.js +2 -2
- package/modules/react/useInstanceMethods.js.map +1 -1
- package/modules/react/useMergeRefs.js +44 -0
- package/modules/react/useMergeRefs.js.map +1 -0
- package/modules/react/{useVirtualScrollerStartStop.js → useStartStopVirtualScroller.js} +1 -1
- package/modules/react/{useVirtualScrollerStartStop.js.map → useStartStopVirtualScroller.js.map} +1 -1
- package/modules/react/useStyle.js +17 -0
- package/modules/react/useStyle.js.map +1 -1
- package/modules/react/useVirtualScroller.js +136 -43
- package/modules/react/useVirtualScroller.js.map +1 -1
- package/package.json +4 -1
- package/react/index.cjs +2 -1
- package/react/index.d.ts +51 -7
- package/react/index.js +1 -0
- package/rollup.config.mjs +15 -1
- package/source/react/VirtualScroller.js +66 -127
- package/source/react/useCreateVirtualScroller.js +65 -0
- package/source/react/useInstanceMethods.js +2 -2
- package/source/react/useMergeRefs.js +45 -0
- package/source/react/useStyle.js +15 -0
- package/source/react/useVirtualScroller.js +155 -48
- package/website/index-dom-bypass.html +3 -4
- package/website/index-dom-grid.html +3 -4
- package/website/index-dom-scrollableContainer.html +3 -4
- package/website/index-dom.html +3 -4
- package/website/index-react-bypass.html +56 -62
- package/website/index-react-grid.html +55 -61
- package/website/index-react-hook.html +209 -0
- package/website/index-react-scrollableContainer.html +56 -62
- package/website/index-react-strictMode.html +55 -61
- package/website/index-react-tbody-scrollableContainer.html +13 -15
- package/website/index-react-tbody.html +10 -12
- package/website/index-react.html +55 -61
- package/website/index.html +55 -61
- package/commonjs/react/useForwardedRef.js +0 -50
- package/commonjs/react/useForwardedRef.js.map +0 -1
- package/modules/react/useForwardedRef.js +0 -42
- package/modules/react/useForwardedRef.js.map +0 -1
- package/source/react/useForwardedRef.js +0 -39
- /package/source/react/{useVirtualScrollerStartStop.js → useStartStopVirtualScroller.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
<!-- `virtual-scroller`: in `.updateItems()` handle a case when `items.length` is the same, in which case find different items and if those items are rendered then maybe update them on screen and update their height, if the items are past rendered then maybe just discard all item heights past rendered, if the items are before rendered then maybe ignore and it will jump on scroll up which is kinda acceptable. -->
|
|
2
2
|
|
|
3
|
+
1.15.1 / 30.11.2025
|
|
4
|
+
===================
|
|
5
|
+
|
|
6
|
+
* Added `useVirtualScroller()` hook that is exported from `virtual-scroller/react` subpackage.
|
|
7
|
+
* Un-deprecated `tbody: boolean` property because it's used in the new hook.
|
|
8
|
+
|
|
3
9
|
1.15.0 / 30.11.2025
|
|
4
10
|
===================
|
|
5
11
|
|
package/README.md
CHANGED
|
@@ -29,6 +29,8 @@ A universal open-source implementation of Twitter's [`VirtualScroller`](https://
|
|
|
29
29
|
* [Table in a scrollable container](https://catamphetamine.gitlab.io/virtual-scroller/index-react-tbody-scrollableContainer.html)
|
|
30
30
|
* [Grid](https://catamphetamine.gitlab.io/virtual-scroller/index-react-grid.html)
|
|
31
31
|
* [Paginated Grid](https://catamphetamine.gitlab.io/virtual-scroller/index-react-grid.html?pagination=✓)
|
|
32
|
+
* [List (using hook)](https://catamphetamine.gitlab.io/virtual-scroller/index-react-hook.html)
|
|
33
|
+
* [Paginated List (using hook)](https://catamphetamine.gitlab.io/virtual-scroller/index-react-hook.html?pagination=✓)
|
|
32
34
|
|
|
33
35
|
## Rationale
|
|
34
36
|
|
|
@@ -172,6 +174,18 @@ function App() {
|
|
|
172
174
|
|
|
173
175
|
<!-- Note: When passing any core `VirtualScroller` class options, only the initial values of those options will be applied, and any updates to those options will be ignored. That's because those options are only passed to the `VirtualScroller` base class constructor at initialization time. That means that none of those options should depend on any variable state or props. For example, if `getColumnsCount()` parameter was defined as `() => props.columnsCount`, then, if the `columnsCount` property changes, the underlying `VirtualScroller` instance won't see that change. -->
|
|
174
176
|
|
|
177
|
+
<!-- I guess that `style` property should be deprecated because it could potentially be dangerous
|
|
178
|
+
due to potential conflicts with `VirtualScroller` styles. It currently isn't present anyway. -->
|
|
179
|
+
<!-- * `style: object` — Custom CSS style, except for `padding-top` or `padding-bottom`. -->
|
|
180
|
+
|
|
181
|
+
<!-- I guess that `className` property should be deprecated because it could potentially be dangerous
|
|
182
|
+
due to potential conflicts with `VirtualScroller` styles. -->
|
|
183
|
+
<!-- * `className: string` — Custom CSS class name. -->
|
|
184
|
+
|
|
185
|
+
* `tbody: boolean` — When the list items container element is going to be a `<tbody/>`, it will have to use a special workaround in order for the `<VirtualScroller/>` to work correctly. To enable this special workaround, a developer could pass a `tbody: true` property. Otherwise, `<VirtualScroller/>` will only enable it when `itemsContainerComponent === "tbody"`.
|
|
186
|
+
<!-- * There's no longer such option in the ["core"](#core) component because it's autodetected there. The reason why it can't always be autodetected in React is because of server-side rendering when there's no items container DOM element whose tag name could be examined to detect the use of a `<tbody/>` tag as an items container. -->
|
|
187
|
+
* Only the initial value of this property is used, and any changes to it will be ignored.
|
|
188
|
+
|
|
175
189
|
* `getColumnsCount(): number` — Returns the count of the columns.
|
|
176
190
|
* This is simply a proxy for the ["core"](#core) component's `getColumnsCount` [option](#options).
|
|
177
191
|
* Only the initial value of this property is used, and any changes to it will be ignored.
|
|
@@ -277,14 +291,6 @@ function ListContainer() {
|
|
|
277
291
|
}
|
|
278
292
|
```
|
|
279
293
|
|
|
280
|
-
<!--
|
|
281
|
-
(this property has been ignored for a long time and was eventually removed)
|
|
282
|
-
|
|
283
|
-
* `tbody: boolean` — When the container for the list items is going to be a `<tbody/>`, a developer must pass a `tbody: true` property in order for the `<VirtualScroller/>` to work correctly.
|
|
284
|
-
* This is simply a proxy for the ["core"](#core) component's `tbody` option.
|
|
285
|
-
* Only the initial value of this property is used, and any changes to it will be ignored.
|
|
286
|
-
-->
|
|
287
|
-
|
|
288
294
|
* `itemsContainerComponentRef: object` — Could be used to get access to the `itemsContainerComponent` instance.
|
|
289
295
|
* For example, if `itemsContainerComponent` is `"ul"` then `itemsContainerComponentRef.current` will be set to the `<ul/>` `Element`.
|
|
290
296
|
|
|
@@ -475,6 +481,90 @@ By default, on server side, it will just render the first item, as if the list o
|
|
|
475
481
|
To fix that, a developer should specify certain properties — `getEstimatedVisibleItemRowsCount(): number` and `getEstimatedItemHeight(): number` and `getEstimatedInterItemVerticalSpacing(): number` — so that it could calculate how many items it should render and how much space it should leave for scrolling. For more technical details, see the description of these parameters in the ["core"](#core) component's [options](#options).
|
|
476
482
|
</details>
|
|
477
483
|
|
|
484
|
+
######
|
|
485
|
+
|
|
486
|
+
<details>
|
|
487
|
+
<summary>Alternatively, instead of using <code><VirtualScroller/></code> component, one could use <code>useVirtualScroller()</code> hook</summary>
|
|
488
|
+
|
|
489
|
+
######
|
|
490
|
+
|
|
491
|
+
```js
|
|
492
|
+
import React from 'react'
|
|
493
|
+
import { useVirtualScroller } from 'virtual-scroller/react'
|
|
494
|
+
|
|
495
|
+
function List(props) {
|
|
496
|
+
const {
|
|
497
|
+
// "Core" component `state`.
|
|
498
|
+
// See "State" section of the readme for more info.
|
|
499
|
+
state: {
|
|
500
|
+
items,
|
|
501
|
+
itemStates,
|
|
502
|
+
firstShownItemIndex,
|
|
503
|
+
lastShownItemIndex
|
|
504
|
+
},
|
|
505
|
+
// CSS style object.
|
|
506
|
+
style,
|
|
507
|
+
// CSS class name.
|
|
508
|
+
className,
|
|
509
|
+
// This `ref` must be passed to the items container component.
|
|
510
|
+
itemsContainerRef,
|
|
511
|
+
// One could use this `virtualScroller` object to call any of its public methods.
|
|
512
|
+
// Except for `virtualScroller.getState()` — use the returned `state` property instead.
|
|
513
|
+
virtualScroller
|
|
514
|
+
} = useVirtualScroller({
|
|
515
|
+
// The properties of `useVirtualScroller()` hook are the same as
|
|
516
|
+
// the properties of `<VirtualScroller/>` component.
|
|
517
|
+
//
|
|
518
|
+
// Additional properties:
|
|
519
|
+
// * `style`
|
|
520
|
+
// * `className`
|
|
521
|
+
//
|
|
522
|
+
// Excluded properties:
|
|
523
|
+
// * `itemComponent`
|
|
524
|
+
// * `itemComponentProps`
|
|
525
|
+
// * `itemsContainerComponent`
|
|
526
|
+
// * `itemsContainerComponentProps`
|
|
527
|
+
//
|
|
528
|
+
items: props.items
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
return (
|
|
532
|
+
<div ref={itemsContainerRef} style={style} className={className}>
|
|
533
|
+
{items.map((item, i) => {
|
|
534
|
+
if (i >= firstShownItemIndex && i <= lastShownItemIndex) {
|
|
535
|
+
return (
|
|
536
|
+
<ListItem
|
|
537
|
+
key={item.id}
|
|
538
|
+
item={item}
|
|
539
|
+
state={itemStates && itemStates[i]}
|
|
540
|
+
/>
|
|
541
|
+
)
|
|
542
|
+
}
|
|
543
|
+
return null
|
|
544
|
+
})}
|
|
545
|
+
</div>
|
|
546
|
+
)
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function ListItem({ item, state }) {
|
|
550
|
+
const { username, date, text } = item
|
|
551
|
+
return (
|
|
552
|
+
<article>
|
|
553
|
+
<a href={`/users/${username}`}>
|
|
554
|
+
@{username}
|
|
555
|
+
</a>
|
|
556
|
+
<time dateTime={date.toISOString()}>
|
|
557
|
+
{date.toString()}
|
|
558
|
+
</time>
|
|
559
|
+
<p>
|
|
560
|
+
{text}
|
|
561
|
+
</p>
|
|
562
|
+
</article>
|
|
563
|
+
)
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
</details>
|
|
567
|
+
|
|
478
568
|
## DOM
|
|
479
569
|
|
|
480
570
|
`virtual-scroller/dom` exports a `VirtualScroller` class that implements a "virtual scroller" in a standard [Document Object Model](https://en.wikipedia.org/wiki/Document_Object_Model) environment such as a web browser.
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
const { toIndex } = getState()
|
|
73
73
|
fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
|
|
74
74
|
setState({
|
|
75
|
+
...getState(),
|
|
75
76
|
fromIndex,
|
|
76
77
|
items: items.slice(fromIndex, toIndex + 1)
|
|
77
78
|
})
|
|
@@ -82,6 +83,7 @@
|
|
|
82
83
|
let { toIndex } = getState()
|
|
83
84
|
toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
|
|
84
85
|
setState({
|
|
86
|
+
...getState(),
|
|
85
87
|
toIndex,
|
|
86
88
|
items: items.slice(fromIndex, toIndex + 1)
|
|
87
89
|
})
|
|
@@ -159,10 +161,7 @@
|
|
|
159
161
|
|
|
160
162
|
setState = (newState) => {
|
|
161
163
|
const prevState = this.state
|
|
162
|
-
this.state =
|
|
163
|
-
...this.state,
|
|
164
|
-
...newState
|
|
165
|
-
}
|
|
164
|
+
this.state = newState
|
|
166
165
|
this.onStateChange(this.state, prevState)
|
|
167
166
|
}
|
|
168
167
|
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
const { toIndex } = getState()
|
|
79
79
|
fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
|
|
80
80
|
setState({
|
|
81
|
+
...getState(),
|
|
81
82
|
fromIndex,
|
|
82
83
|
items: items.slice(fromIndex, toIndex + 1)
|
|
83
84
|
})
|
|
@@ -88,6 +89,7 @@
|
|
|
88
89
|
let { toIndex } = getState()
|
|
89
90
|
toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
|
|
90
91
|
setState({
|
|
92
|
+
...getState(),
|
|
91
93
|
toIndex,
|
|
92
94
|
items: items.slice(fromIndex, toIndex + 1)
|
|
93
95
|
})
|
|
@@ -165,10 +167,7 @@
|
|
|
165
167
|
|
|
166
168
|
setState = (newState) => {
|
|
167
169
|
const prevState = this.state
|
|
168
|
-
this.state =
|
|
169
|
-
...this.state,
|
|
170
|
-
...newState
|
|
171
|
-
}
|
|
170
|
+
this.state = newState
|
|
172
171
|
this.onStateChange(this.state, prevState)
|
|
173
172
|
}
|
|
174
173
|
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
const { toIndex } = getState()
|
|
86
86
|
fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
|
|
87
87
|
setState({
|
|
88
|
+
...getState(),
|
|
88
89
|
fromIndex,
|
|
89
90
|
items: items.slice(fromIndex, toIndex + 1)
|
|
90
91
|
})
|
|
@@ -95,6 +96,7 @@
|
|
|
95
96
|
let { toIndex } = getState()
|
|
96
97
|
toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
|
|
97
98
|
setState({
|
|
99
|
+
...getState(),
|
|
98
100
|
toIndex,
|
|
99
101
|
items: items.slice(fromIndex, toIndex + 1)
|
|
100
102
|
})
|
|
@@ -176,10 +178,7 @@
|
|
|
176
178
|
|
|
177
179
|
setState = (newState) => {
|
|
178
180
|
const prevState = this.state
|
|
179
|
-
this.state =
|
|
180
|
-
...this.state,
|
|
181
|
-
...newState
|
|
182
|
-
}
|
|
181
|
+
this.state = newState
|
|
183
182
|
this.onStateChange(this.state, prevState)
|
|
184
183
|
}
|
|
185
184
|
|
package/bundle/index-dom.html
CHANGED
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
const { toIndex } = getState()
|
|
73
73
|
fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
|
|
74
74
|
setState({
|
|
75
|
+
...getState(),
|
|
75
76
|
fromIndex,
|
|
76
77
|
items: items.slice(fromIndex, toIndex + 1)
|
|
77
78
|
})
|
|
@@ -82,6 +83,7 @@
|
|
|
82
83
|
let { toIndex } = getState()
|
|
83
84
|
toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
|
|
84
85
|
setState({
|
|
86
|
+
...getState(),
|
|
85
87
|
toIndex,
|
|
86
88
|
items: items.slice(fromIndex, toIndex + 1)
|
|
87
89
|
})
|
|
@@ -159,10 +161,7 @@
|
|
|
159
161
|
|
|
160
162
|
setState = (newState) => {
|
|
161
163
|
const prevState = this.state
|
|
162
|
-
this.state =
|
|
163
|
-
...this.state,
|
|
164
|
-
...newState
|
|
165
|
-
}
|
|
164
|
+
this.state = newState
|
|
166
165
|
this.onStateChange(this.state, prevState)
|
|
167
166
|
}
|
|
168
167
|
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
const { toIndex } = getState()
|
|
65
65
|
fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
|
|
66
66
|
setState({
|
|
67
|
+
...getState(),
|
|
67
68
|
fromIndex,
|
|
68
69
|
items: items.slice(fromIndex, toIndex + 1)
|
|
69
70
|
})
|
|
@@ -74,64 +75,59 @@
|
|
|
74
75
|
let { toIndex } = getState()
|
|
75
76
|
toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
|
|
76
77
|
setState({
|
|
78
|
+
...getState(),
|
|
77
79
|
toIndex,
|
|
78
80
|
items: items.slice(fromIndex, toIndex + 1)
|
|
79
81
|
})
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
super(props)
|
|
84
|
+
function VirtualScrollerDemo() {
|
|
85
|
+
const [state, setState] = React.useState(getInitialState(ITEMS))
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
getState = () => this.state
|
|
87
|
+
const getState = () => state
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
onShowPrevious(ITEMS,
|
|
89
|
+
const onShowPrevious_ = () => {
|
|
90
|
+
onShowPrevious(ITEMS, getState, setState)
|
|
93
91
|
}
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
onShowNext(ITEMS,
|
|
93
|
+
const onShowNext_ = () => {
|
|
94
|
+
onShowNext(ITEMS, getState, setState)
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
)
|
|
134
|
-
}
|
|
97
|
+
const {
|
|
98
|
+
fromIndex,
|
|
99
|
+
toIndex,
|
|
100
|
+
items
|
|
101
|
+
} = state
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<React.Fragment>
|
|
105
|
+
{window.PAGINATION && fromIndex > 0 &&
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
onClick={onShowPrevious_}
|
|
109
|
+
className="load-items-button">
|
|
110
|
+
Show previous
|
|
111
|
+
</button>
|
|
112
|
+
}
|
|
113
|
+
<VirtualScroller
|
|
114
|
+
bypass
|
|
115
|
+
id="list"
|
|
116
|
+
items={items}
|
|
117
|
+
itemComponent={Item}
|
|
118
|
+
preserveScrollPositionOnPrependItems
|
|
119
|
+
getColumnsCount={getColumnsCount}
|
|
120
|
+
/>
|
|
121
|
+
{window.PAGINATION && toIndex < ITEMS.length - 1 &&
|
|
122
|
+
<button
|
|
123
|
+
type="button"
|
|
124
|
+
onClick={onShowNext_}
|
|
125
|
+
className="load-items-button">
|
|
126
|
+
Show next
|
|
127
|
+
</button>
|
|
128
|
+
}
|
|
129
|
+
</React.Fragment>
|
|
130
|
+
)
|
|
135
131
|
}
|
|
136
132
|
|
|
137
133
|
const item = PropTypes.shape({
|
|
@@ -168,21 +164,19 @@
|
|
|
168
164
|
children: item.isRequired
|
|
169
165
|
}
|
|
170
166
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
<
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
)
|
|
185
|
-
}
|
|
167
|
+
function Demo() {
|
|
168
|
+
return (
|
|
169
|
+
<section className="container">
|
|
170
|
+
<h1>
|
|
171
|
+
<TwitterLogo/>
|
|
172
|
+
Latest Tweets on #politics
|
|
173
|
+
</h1>
|
|
174
|
+
<VirtualScrollerDemo/>
|
|
175
|
+
<footer>
|
|
176
|
+
© Twitter Inc., 2019
|
|
177
|
+
</footer>
|
|
178
|
+
</section>
|
|
179
|
+
)
|
|
186
180
|
}
|
|
187
181
|
|
|
188
182
|
function TwitterLogo() {
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
const { toIndex } = getState()
|
|
69
69
|
fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
|
|
70
70
|
setState({
|
|
71
|
+
...getState(),
|
|
71
72
|
fromIndex,
|
|
72
73
|
items: items.slice(fromIndex, toIndex + 1)
|
|
73
74
|
})
|
|
@@ -78,63 +79,58 @@
|
|
|
78
79
|
let { toIndex } = getState()
|
|
79
80
|
toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
|
|
80
81
|
setState({
|
|
82
|
+
...getState(),
|
|
81
83
|
toIndex,
|
|
82
84
|
items: items.slice(fromIndex, toIndex + 1)
|
|
83
85
|
})
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
super(props)
|
|
88
|
+
function VirtualScrollerDemo() {
|
|
89
|
+
const [state, setState] = React.useState(getInitialState(ITEMS))
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
getState = () => this.state
|
|
91
|
+
const getState = () => state
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
onShowPrevious(ITEMS,
|
|
93
|
+
const onShowPrevious_ = () => {
|
|
94
|
+
onShowPrevious(ITEMS, getState, setState)
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
|
|
100
|
-
onShowNext(ITEMS,
|
|
97
|
+
const onShowNext_ = () => {
|
|
98
|
+
onShowNext(ITEMS, getState, setState)
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
137
|
-
}
|
|
101
|
+
const {
|
|
102
|
+
fromIndex,
|
|
103
|
+
toIndex,
|
|
104
|
+
items
|
|
105
|
+
} = state
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<React.Fragment>
|
|
109
|
+
{window.PAGINATION && fromIndex > 0 &&
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
112
|
+
onClick={onShowPrevious_}
|
|
113
|
+
className="load-items-button">
|
|
114
|
+
Show previous
|
|
115
|
+
</button>
|
|
116
|
+
}
|
|
117
|
+
<VirtualScroller
|
|
118
|
+
id="list"
|
|
119
|
+
items={items}
|
|
120
|
+
itemComponent={Item}
|
|
121
|
+
preserveScrollPositionOnPrependItems
|
|
122
|
+
getColumnsCount={getColumnsCount}
|
|
123
|
+
/>
|
|
124
|
+
{window.PAGINATION && toIndex < ITEMS.length - 1 &&
|
|
125
|
+
<button
|
|
126
|
+
type="button"
|
|
127
|
+
onClick={onShowNext_}
|
|
128
|
+
className="load-items-button">
|
|
129
|
+
Show next
|
|
130
|
+
</button>
|
|
131
|
+
}
|
|
132
|
+
</React.Fragment>
|
|
133
|
+
)
|
|
138
134
|
}
|
|
139
135
|
|
|
140
136
|
const item = PropTypes.shape({
|
|
@@ -171,21 +167,19 @@
|
|
|
171
167
|
children: item.isRequired
|
|
172
168
|
}
|
|
173
169
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
)
|
|
188
|
-
}
|
|
170
|
+
function Demo() {
|
|
171
|
+
return (
|
|
172
|
+
<section className="container">
|
|
173
|
+
<h1>
|
|
174
|
+
<TwitterLogo/>
|
|
175
|
+
Latest Tweets on #politics
|
|
176
|
+
</h1>
|
|
177
|
+
<VirtualScrollerDemo/>
|
|
178
|
+
<footer>
|
|
179
|
+
© Twitter Inc., 2019
|
|
180
|
+
</footer>
|
|
181
|
+
</section>
|
|
182
|
+
)
|
|
189
183
|
}
|
|
190
184
|
|
|
191
185
|
function TwitterLogo() {
|