Skip to content

Commit 2268059

Browse files
authored
feat(VirtualizedList)!: remove numberOfElementsVisibleOnScreen and numberOfElementsRendered props (#153)
* feat!: remove numberOfItemsVisibleOnScreen prop from VirtualizedList * feat: change numberOfElementsRendered to additionalElementsRendered * fix: types error after refactor * refactor: move files to helpers * feat: update doc * feat: remove throw on values of nbOfElementsRendered * chore: remove unnecessary ternary * test: fixing tests * fix: remove throw on empty list * refactor: switch to object args for numberOfItemsVisibleOnScreenFunctions * chore: handle undefined index accesses * chore: handle length edge cases
1 parent af37542 commit 2268059

14 files changed

Lines changed: 436 additions & 612 deletions

docs/api.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,7 @@ It also ensures that the scroll event is propagated properly to parent ScrollVie
241241
| `data` | `Array<T>` | The array of data items to render. ⚠️ You should memoize this array for maximum performance. A costly memo depends on it. |
242242
| `renderItem` | `(args: { item: T }) => JSX.Element` | A function that returns the JSX element to render for each item in the data array. The function receives an object with the item as a parameter. |
243243
| `itemSize` | `number \| ((item: T) => number)` | In case you specify a number it will behave like this : ff vertical, the height of an item; otherwise, the width. You can also specify a function which needs to return for each item of `data` its size in pixel in order for the list to handle various item sizes. ⚠️ You should memoize this function for maximal performances. An important memo depends on it. |
244-
| `numberOfRenderedItems` | `number` | The number of items to be rendered (virtualization size). ⚠️ It must be at least equal to `numberOfItemsVisibleOnScreen +2` or when using jump-on-scroll : `(2 * numberOfItemsVisibleOnScreen) + 1` to ensure correct rendering. |
245-
| `numberOfItemsVisibleOnScreen` | `number` | The number of items visible on the screen. This helps determine how to slice the data and when to stop the scroll at the end of the list. |
244+
| `additionalItemsRendered` | `number` | Optional : The number of items to be rendered (virtualization size) additionally to the elements visible on screen. Base value is 4 for `stick-to-start` and `stick-to-end` scrolls, and twice the number of elements visible for `jump-on-scroll`. |
246245
| `onEndReached` | `() => void` | An optional callback function that is called when the user reaches the end of the list. Helps with pagination. |
247246
| `onEndReachedThresholdItemsNumber` | `number` | The number of items left to display before triggering the `onEndReached` callback. Defaults to 3. |
248247
| `style` | `ViewStyle` | Custom style to be applied to the VirtualizedList container. |
@@ -319,10 +318,9 @@ VirtualizedGrids only support vertical orientation (vertically scrollable), but
319318
| `renderItem` | `(args: { item: T }) => JSX.Element` | A function that returns the JSX element to render for each item in the data array. The function receives an object with the item as a parameter. |
320319
| `numberOfColumns` | `Number` | The number of columns in the grid or the number of items per row. |
321320
| `itemHeight` | `Number` | The height of each item in the grid. |
322-
| `numberOfRenderedRows` | `Number` | How many rows are rendered (virtualization size). |
321+
| `additionalRenderedRows` | `Number` | Optional : The number of rows to be rendered (virtualization size) additionally to the rows visible on screen. Base value is 4 for `stick-to-start` and `stick-to-end` scrolls, and twice the number of elements visible for `jump-on-scroll`. |
323322
| `header` | `JSX.Element` | Optional header component you can provide to display at the top of a virtualized grid. If provided, you also need to provide its size (so that the grid knows how to scroll) |
324323
| `headerSize` | `Number` | The Size in pixels of the (optionnally) provided header. |
325-
| `numberOfRowsVisibleOnScreen` | `Number` | How many rows are visible on the screen (helps with knowing how to slice the data and stop the scroll at the end of the list). |
326324
| `onEndReached` | `() => void` | An optional callback function that is called when the user reaches the end of the list. Helps with pagination. |
327325
| `onEndReachedThresholdRowsNumber` | `Number` | Number of rows left to display before triggering the onEndReached event. |
328326
| `style` | `Object` | Used to modify the style of the grid. |
@@ -354,8 +352,7 @@ const renderItem = ({ item }) => {
354352
renderItem={renderItem}
355353
numberOfColumns={3}
356354
itemHeight={100}
357-
numberOfRenderedRows={7}
358-
numberOfRowsVisibleOnScreen={3}
355+
additionalItemsRendered={5}
359356
onEndReachedThresholdRowsNumber={2}
360357
rowContainerStyle={{gap: 15}}
361358
/>

packages/example/src/components/VirtualizedSpatialGrid.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import { Header } from '../modules/header/view/Header';
1010
import { BottomArrow, TopArrow } from '../design-system/components/Arrows';
1111
import { ProgramInfo } from '../modules/program/domain/programInfo';
1212

13-
const NUMBER_OF_ROWS_VISIBLE_ON_SCREEN = 2;
14-
const NUMBER_OF_RENDERED_ROWS = NUMBER_OF_ROWS_VISIBLE_ON_SCREEN + 5;
1513
const NUMBER_OF_COLUMNS = 7;
1614
const INFINITE_SCROLL_ROW_THRESHOLD = 2;
1715

@@ -44,8 +42,6 @@ export const VirtualizedSpatialGrid = ({ containerStyle }: { containerStyle?: Vi
4442
renderItem={renderItem}
4543
itemHeight={theme.sizes.program.portrait.height * 1.1}
4644
numberOfColumns={NUMBER_OF_COLUMNS}
47-
numberOfRenderedRows={NUMBER_OF_RENDERED_ROWS}
48-
numberOfRowsVisibleOnScreen={NUMBER_OF_ROWS_VISIBLE_ON_SCREEN}
4945
onEndReachedThresholdRowsNumber={INFINITE_SCROLL_ROW_THRESHOLD}
5046
rowContainerStyle={styles.rowStyle}
5147
ascendingArrow={<BottomArrow />}

packages/example/src/modules/program/view/ProgramList.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import { useKey } from '../../../hooks/useKey';
2121
import React from 'react';
2222

2323
const NUMBER_OF_ITEMS_VISIBLE_ON_SCREEN = 7;
24-
const WINDOW_SIZE = NUMBER_OF_ITEMS_VISIBLE_ON_SCREEN + 8;
2524
const ROW_PADDING = scaledPixels(70);
2625

2726
const GAP_BETWEEN_ELEMENTS = scaledPixels(30);
@@ -101,8 +100,6 @@ export const ProgramList = React.forwardRef<View, ProgramListProps>(
101100
data={programInfos}
102101
renderItem={renderItem}
103102
itemSize={itemSize}
104-
numberOfRenderedItems={WINDOW_SIZE}
105-
numberOfItemsVisibleOnScreen={NUMBER_OF_ITEMS_VISIBLE_ON_SCREEN}
106103
onEndReachedThresholdItemsNumber={NUMBER_OF_ITEMS_VISIBLE_ON_SCREEN}
107104
// @ts-expect-error TODO change the type from ReactElement to ReactNode in the core
108105
descendingArrow={isActive ? <LeftArrow /> : null}

packages/lib/src/spatial-navigation/components/virtualizedGrid/SpatialNavigationVirtualizedGrid.test.tsx

Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,8 @@ describe('SpatialNavigationVirtualizedGrid', () => {
3838
<DefaultFocus>
3939
<SpatialNavigationVirtualizedGrid
4040
renderItem={renderItem}
41-
data={createDataArray(19)}
41+
data={createDataArray(28)}
4242
itemHeight={100}
43-
numberOfRenderedRows={5}
44-
numberOfRowsVisibleOnScreen={3}
4543
numberOfColumns={3}
4644
testID="test-grid"
4745
/>
@@ -56,7 +54,7 @@ describe('SpatialNavigationVirtualizedGrid', () => {
5654
expect(screen).toMatchSnapshot();
5755

5856
const listElement = component.getByTestId(gridTestId);
59-
expect(listElement).toHaveStyle({ height: 700 });
57+
expect(listElement).toHaveStyle({ height: 1000 });
6058

6159
expect(screen.getByText('button 1')).toBeTruthy();
6260
expectButtonToHaveFocus(component, 'button 1');
@@ -74,7 +72,13 @@ describe('SpatialNavigationVirtualizedGrid', () => {
7472
expect(screen.getByText('button 13')).toBeTruthy();
7573
expect(screen.getByText('button 14')).toBeTruthy();
7674
expect(screen.getByText('button 15')).toBeTruthy();
77-
expect(screen.queryByText('button 16')).toBeFalsy();
75+
expect(screen.getByText('button 16')).toBeTruthy();
76+
expect(screen.getByText('button 17')).toBeTruthy();
77+
expect(screen.getByText('button 18')).toBeTruthy();
78+
expect(screen.getByText('button 19')).toBeTruthy();
79+
expect(screen.getByText('button 20')).toBeTruthy();
80+
expect(screen.getByText('button 21')).toBeTruthy();
81+
expect(screen.queryByText('button 22')).toBeFalsy();
7882
});
7983

8084
it('handles correctly RIGHT & DOWN and RENDERS new elements accordingly while deleting elements that are too far from scroll when on stick to start scroll', () => {
@@ -84,7 +88,7 @@ describe('SpatialNavigationVirtualizedGrid', () => {
8488

8589
const listElement = component.getByTestId(gridTestId);
8690
expectListToHaveScroll(listElement, 0);
87-
expect(listElement).toHaveStyle({ height: 700 });
91+
expect(listElement).toHaveStyle({ height: 1000 });
8892

8993
testRemoteControlManager.handleRight();
9094

@@ -104,70 +108,69 @@ describe('SpatialNavigationVirtualizedGrid', () => {
104108
expect(screen.getByText('button 13')).toBeTruthy();
105109
expect(screen.getByText('button 14')).toBeTruthy();
106110
expect(screen.getByText('button 15')).toBeTruthy();
107-
expect(screen.queryByText('button 16')).toBeFalsy();
111+
expect(screen.getByText('button 16')).toBeTruthy();
112+
expect(screen.getByText('button 17')).toBeTruthy();
113+
expect(screen.getByText('button 18')).toBeTruthy();
114+
expect(screen.getByText('button 19')).toBeTruthy();
115+
expect(screen.getByText('button 20')).toBeTruthy();
116+
expect(screen.getByText('button 21')).toBeTruthy();
117+
expect(screen.queryByText('button 22')).toBeFalsy();
108118

109119
testRemoteControlManager.handleDown();
110120
expectListToHaveScroll(listElement, -100);
111-
112-
expect(screen.getByText('button 1')).toBeTruthy();
113-
expect(screen.getByText('button 2')).toBeTruthy();
114-
expect(screen.getByText('button 3')).toBeTruthy();
115-
expect(screen.getByText('button 4')).toBeTruthy();
116-
expect(screen.getByText('button 5')).toBeTruthy();
117121
expectButtonToHaveFocus(component, 'button 5');
118-
expect(screen.getByText('button 6')).toBeTruthy();
119-
expect(screen.getByText('button 7')).toBeTruthy();
120-
expect(screen.getByText('button 8')).toBeTruthy();
121-
expect(screen.getByText('button 9')).toBeTruthy();
122-
expect(screen.getByText('button 10')).toBeTruthy();
123-
expect(screen.getByText('button 11')).toBeTruthy();
124-
expect(screen.getByText('button 12')).toBeTruthy();
125-
expect(screen.getByText('button 13')).toBeTruthy();
126-
expect(screen.getByText('button 14')).toBeTruthy();
127-
expect(screen.getByText('button 15')).toBeTruthy();
128-
expect(screen.queryByText('button 16')).toBeFalsy();
129122

130123
testRemoteControlManager.handleDown();
131124
expectListToHaveScroll(listElement, -200);
125+
expectButtonToHaveFocus(component, 'button 8');
126+
127+
testRemoteControlManager.handleDown();
128+
expectListToHaveScroll(listElement, -300);
129+
expectButtonToHaveFocus(component, 'button 11');
132130

133131
expect(screen.queryByText('button 1')).toBeFalsy();
134132
expect(screen.queryByText('button 2')).toBeFalsy();
135133
expect(screen.queryByText('button 3')).toBeFalsy();
136134
expect(screen.getByText('button 4')).toBeTruthy();
137-
expect(screen.getByText('button 5')).toBeTruthy();
138-
expect(screen.getByText('button 6')).toBeTruthy();
135+
136+
testRemoteControlManager.handleDown();
137+
expectListToHaveScroll(listElement, -400);
138+
expectButtonToHaveFocus(component, 'button 14');
139+
140+
expect(screen.queryByText('button 4')).toBeFalsy();
141+
expect(screen.queryByText('button 5')).toBeFalsy();
142+
expect(screen.queryByText('button 6')).toBeFalsy();
139143
expect(screen.getByText('button 7')).toBeTruthy();
140-
expect(screen.getByText('button 8')).toBeTruthy();
141-
expectButtonToHaveFocus(component, 'button 8');
142-
expect(screen.getByText('button 9')).toBeTruthy();
143-
expect(screen.getByText('button 10')).toBeTruthy();
144-
expect(screen.getByText('button 11')).toBeTruthy();
145-
expect(screen.getByText('button 12')).toBeTruthy();
146-
expect(screen.getByText('button 13')).toBeTruthy();
147-
expect(screen.getByText('button 14')).toBeTruthy();
148-
expect(screen.getByText('button 15')).toBeTruthy();
149-
expect(screen.getByText('button 16')).toBeTruthy();
150-
expect(screen.getByText('button 17')).toBeTruthy();
151-
expect(screen.getByText('button 18')).toBeTruthy();
152-
expect(screen.queryByText('button 19')).toBeFalsy();
153144

154-
expect(screen).toMatchSnapshot();
145+
testRemoteControlManager.handleDown();
146+
expectListToHaveScroll(listElement, -500);
147+
expectButtonToHaveFocus(component, 'button 17');
148+
149+
expect(screen.queryByText('button 7')).toBeFalsy();
150+
expect(screen.queryByText('button 8')).toBeFalsy();
151+
expect(screen.queryByText('button 9')).toBeFalsy();
152+
expect(screen.getByText('button 10')).toBeTruthy();
155153

156154
testRemoteControlManager.handleDown();
157-
expectListToHaveScroll(listElement, -300);
158-
expectButtonToHaveFocus(component, 'button 11');
155+
expectListToHaveScroll(listElement, -600);
156+
expectButtonToHaveFocus(component, 'button 20');
157+
158+
expect(screen.queryByText('button 7')).toBeFalsy();
159+
expect(screen.queryByText('button 8')).toBeFalsy();
160+
expect(screen.queryByText('button 9')).toBeFalsy();
161+
expect(screen.getByText('button 10')).toBeTruthy();
159162

160163
testRemoteControlManager.handleDown();
161-
expectListToHaveScroll(listElement, -400);
162-
expectButtonToHaveFocus(component, 'button 14');
164+
expectListToHaveScroll(listElement, -700);
165+
expectButtonToHaveFocus(component, 'button 23');
163166

164167
testRemoteControlManager.handleDown();
165-
expectListToHaveScroll(listElement, -400);
166-
expectButtonToHaveFocus(component, 'button 17');
168+
expectListToHaveScroll(listElement, -700);
169+
expectButtonToHaveFocus(component, 'button 26');
167170

168171
testRemoteControlManager.handleDown();
169-
expectListToHaveScroll(listElement, -400);
170-
expectButtonToHaveFocus(component, 'button 19');
172+
expectListToHaveScroll(listElement, -700);
173+
expectButtonToHaveFocus(component, 'button 28');
171174
});
172175

173176
it('handles correctly RIGHT & DOWN and RENDERS new elements accordingly while deleting elements that are too far from scroll when on stick to end scroll', () => {
@@ -178,8 +181,6 @@ describe('SpatialNavigationVirtualizedGrid', () => {
178181
renderItem={renderItem}
179182
data={createDataArray(19)}
180183
itemHeight={100}
181-
numberOfRenderedRows={5}
182-
numberOfRowsVisibleOnScreen={3}
183184
numberOfColumns={3}
184185
testID="test-grid"
185186
scrollBehavior="stick-to-end"
@@ -231,8 +232,6 @@ describe('SpatialNavigationVirtualizedGrid', () => {
231232
renderItem={renderItem}
232233
data={createDataArray(19)}
233234
itemHeight={100}
234-
numberOfRenderedRows={7}
235-
numberOfRowsVisibleOnScreen={3}
236235
numberOfColumns={3}
237236
testID="test-grid"
238237
scrollBehavior="jump-on-scroll"

0 commit comments

Comments
 (0)