Skip to content

Commit

Permalink
feat(VirtualizedList)!: remove numberOfElementsVisibleOnScreen and nu…
Browse files Browse the repository at this point in the history
…mberOfElementsRendered 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
  • Loading branch information
JulienIzz authored Oct 8, 2024
1 parent af37542 commit 2268059
Show file tree
Hide file tree
Showing 14 changed files with 436 additions and 612 deletions.
9 changes: 3 additions & 6 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@ It also ensures that the scroll event is propagated properly to parent ScrollVie
| `data` | `Array<T>` | The array of data items to render. ⚠️ You should memoize this array for maximum performance. A costly memo depends on it. |
| `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. |
| `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. |
| `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. |
| `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. |
| `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`. |
| `onEndReached` | `() => void` | An optional callback function that is called when the user reaches the end of the list. Helps with pagination. |
| `onEndReachedThresholdItemsNumber` | `number` | The number of items left to display before triggering the `onEndReached` callback. Defaults to 3. |
| `style` | `ViewStyle` | Custom style to be applied to the VirtualizedList container. |
Expand Down Expand Up @@ -319,10 +318,9 @@ VirtualizedGrids only support vertical orientation (vertically scrollable), but
| `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. |
| `numberOfColumns` | `Number` | The number of columns in the grid or the number of items per row. |
| `itemHeight` | `Number` | The height of each item in the grid. |
| `numberOfRenderedRows` | `Number` | How many rows are rendered (virtualization size). |
| `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`. |
| `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) |
| `headerSize` | `Number` | The Size in pixels of the (optionnally) provided header. |
| `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). |
| `onEndReached` | `() => void` | An optional callback function that is called when the user reaches the end of the list. Helps with pagination. |
| `onEndReachedThresholdRowsNumber` | `Number` | Number of rows left to display before triggering the onEndReached event. |
| `style` | `Object` | Used to modify the style of the grid. |
Expand Down Expand Up @@ -354,8 +352,7 @@ const renderItem = ({ item }) => {
renderItem={renderItem}
numberOfColumns={3}
itemHeight={100}
numberOfRenderedRows={7}
numberOfRowsVisibleOnScreen={3}
additionalItemsRendered={5}
onEndReachedThresholdRowsNumber={2}
rowContainerStyle={{gap: 15}}
/>
Expand Down
4 changes: 0 additions & 4 deletions packages/example/src/components/VirtualizedSpatialGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { Header } from '../modules/header/view/Header';
import { BottomArrow, TopArrow } from '../design-system/components/Arrows';
import { ProgramInfo } from '../modules/program/domain/programInfo';

const NUMBER_OF_ROWS_VISIBLE_ON_SCREEN = 2;
const NUMBER_OF_RENDERED_ROWS = NUMBER_OF_ROWS_VISIBLE_ON_SCREEN + 5;
const NUMBER_OF_COLUMNS = 7;
const INFINITE_SCROLL_ROW_THRESHOLD = 2;

Expand Down Expand Up @@ -44,8 +42,6 @@ export const VirtualizedSpatialGrid = ({ containerStyle }: { containerStyle?: Vi
renderItem={renderItem}
itemHeight={theme.sizes.program.portrait.height * 1.1}
numberOfColumns={NUMBER_OF_COLUMNS}
numberOfRenderedRows={NUMBER_OF_RENDERED_ROWS}
numberOfRowsVisibleOnScreen={NUMBER_OF_ROWS_VISIBLE_ON_SCREEN}
onEndReachedThresholdRowsNumber={INFINITE_SCROLL_ROW_THRESHOLD}
rowContainerStyle={styles.rowStyle}
ascendingArrow={<BottomArrow />}
Expand Down
3 changes: 0 additions & 3 deletions packages/example/src/modules/program/view/ProgramList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { useKey } from '../../../hooks/useKey';
import React from 'react';

const NUMBER_OF_ITEMS_VISIBLE_ON_SCREEN = 7;
const WINDOW_SIZE = NUMBER_OF_ITEMS_VISIBLE_ON_SCREEN + 8;
const ROW_PADDING = scaledPixels(70);

const GAP_BETWEEN_ELEMENTS = scaledPixels(30);
Expand Down Expand Up @@ -101,8 +100,6 @@ export const ProgramList = React.forwardRef<View, ProgramListProps>(
data={programInfos}
renderItem={renderItem}
itemSize={itemSize}
numberOfRenderedItems={WINDOW_SIZE}
numberOfItemsVisibleOnScreen={NUMBER_OF_ITEMS_VISIBLE_ON_SCREEN}
onEndReachedThresholdItemsNumber={NUMBER_OF_ITEMS_VISIBLE_ON_SCREEN}
// @ts-expect-error TODO change the type from ReactElement to ReactNode in the core
descendingArrow={isActive ? <LeftArrow /> : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,8 @@ describe('SpatialNavigationVirtualizedGrid', () => {
<DefaultFocus>
<SpatialNavigationVirtualizedGrid
renderItem={renderItem}
data={createDataArray(19)}
data={createDataArray(28)}
itemHeight={100}
numberOfRenderedRows={5}
numberOfRowsVisibleOnScreen={3}
numberOfColumns={3}
testID="test-grid"
/>
Expand All @@ -56,7 +54,7 @@ describe('SpatialNavigationVirtualizedGrid', () => {
expect(screen).toMatchSnapshot();

const listElement = component.getByTestId(gridTestId);
expect(listElement).toHaveStyle({ height: 700 });
expect(listElement).toHaveStyle({ height: 1000 });

expect(screen.getByText('button 1')).toBeTruthy();
expectButtonToHaveFocus(component, 'button 1');
Expand All @@ -74,7 +72,13 @@ describe('SpatialNavigationVirtualizedGrid', () => {
expect(screen.getByText('button 13')).toBeTruthy();
expect(screen.getByText('button 14')).toBeTruthy();
expect(screen.getByText('button 15')).toBeTruthy();
expect(screen.queryByText('button 16')).toBeFalsy();
expect(screen.getByText('button 16')).toBeTruthy();
expect(screen.getByText('button 17')).toBeTruthy();
expect(screen.getByText('button 18')).toBeTruthy();
expect(screen.getByText('button 19')).toBeTruthy();
expect(screen.getByText('button 20')).toBeTruthy();
expect(screen.getByText('button 21')).toBeTruthy();
expect(screen.queryByText('button 22')).toBeFalsy();
});

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', () => {
Expand All @@ -84,7 +88,7 @@ describe('SpatialNavigationVirtualizedGrid', () => {

const listElement = component.getByTestId(gridTestId);
expectListToHaveScroll(listElement, 0);
expect(listElement).toHaveStyle({ height: 700 });
expect(listElement).toHaveStyle({ height: 1000 });

testRemoteControlManager.handleRight();

Expand All @@ -104,70 +108,69 @@ describe('SpatialNavigationVirtualizedGrid', () => {
expect(screen.getByText('button 13')).toBeTruthy();
expect(screen.getByText('button 14')).toBeTruthy();
expect(screen.getByText('button 15')).toBeTruthy();
expect(screen.queryByText('button 16')).toBeFalsy();
expect(screen.getByText('button 16')).toBeTruthy();
expect(screen.getByText('button 17')).toBeTruthy();
expect(screen.getByText('button 18')).toBeTruthy();
expect(screen.getByText('button 19')).toBeTruthy();
expect(screen.getByText('button 20')).toBeTruthy();
expect(screen.getByText('button 21')).toBeTruthy();
expect(screen.queryByText('button 22')).toBeFalsy();

testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -100);

expect(screen.getByText('button 1')).toBeTruthy();
expect(screen.getByText('button 2')).toBeTruthy();
expect(screen.getByText('button 3')).toBeTruthy();
expect(screen.getByText('button 4')).toBeTruthy();
expect(screen.getByText('button 5')).toBeTruthy();
expectButtonToHaveFocus(component, 'button 5');
expect(screen.getByText('button 6')).toBeTruthy();
expect(screen.getByText('button 7')).toBeTruthy();
expect(screen.getByText('button 8')).toBeTruthy();
expect(screen.getByText('button 9')).toBeTruthy();
expect(screen.getByText('button 10')).toBeTruthy();
expect(screen.getByText('button 11')).toBeTruthy();
expect(screen.getByText('button 12')).toBeTruthy();
expect(screen.getByText('button 13')).toBeTruthy();
expect(screen.getByText('button 14')).toBeTruthy();
expect(screen.getByText('button 15')).toBeTruthy();
expect(screen.queryByText('button 16')).toBeFalsy();

testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -200);
expectButtonToHaveFocus(component, 'button 8');

testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -300);
expectButtonToHaveFocus(component, 'button 11');

expect(screen.queryByText('button 1')).toBeFalsy();
expect(screen.queryByText('button 2')).toBeFalsy();
expect(screen.queryByText('button 3')).toBeFalsy();
expect(screen.getByText('button 4')).toBeTruthy();
expect(screen.getByText('button 5')).toBeTruthy();
expect(screen.getByText('button 6')).toBeTruthy();

testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -400);
expectButtonToHaveFocus(component, 'button 14');

expect(screen.queryByText('button 4')).toBeFalsy();
expect(screen.queryByText('button 5')).toBeFalsy();
expect(screen.queryByText('button 6')).toBeFalsy();
expect(screen.getByText('button 7')).toBeTruthy();
expect(screen.getByText('button 8')).toBeTruthy();
expectButtonToHaveFocus(component, 'button 8');
expect(screen.getByText('button 9')).toBeTruthy();
expect(screen.getByText('button 10')).toBeTruthy();
expect(screen.getByText('button 11')).toBeTruthy();
expect(screen.getByText('button 12')).toBeTruthy();
expect(screen.getByText('button 13')).toBeTruthy();
expect(screen.getByText('button 14')).toBeTruthy();
expect(screen.getByText('button 15')).toBeTruthy();
expect(screen.getByText('button 16')).toBeTruthy();
expect(screen.getByText('button 17')).toBeTruthy();
expect(screen.getByText('button 18')).toBeTruthy();
expect(screen.queryByText('button 19')).toBeFalsy();

expect(screen).toMatchSnapshot();
testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -500);
expectButtonToHaveFocus(component, 'button 17');

expect(screen.queryByText('button 7')).toBeFalsy();
expect(screen.queryByText('button 8')).toBeFalsy();
expect(screen.queryByText('button 9')).toBeFalsy();
expect(screen.getByText('button 10')).toBeTruthy();

testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -300);
expectButtonToHaveFocus(component, 'button 11');
expectListToHaveScroll(listElement, -600);
expectButtonToHaveFocus(component, 'button 20');

expect(screen.queryByText('button 7')).toBeFalsy();
expect(screen.queryByText('button 8')).toBeFalsy();
expect(screen.queryByText('button 9')).toBeFalsy();
expect(screen.getByText('button 10')).toBeTruthy();

testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -400);
expectButtonToHaveFocus(component, 'button 14');
expectListToHaveScroll(listElement, -700);
expectButtonToHaveFocus(component, 'button 23');

testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -400);
expectButtonToHaveFocus(component, 'button 17');
expectListToHaveScroll(listElement, -700);
expectButtonToHaveFocus(component, 'button 26');

testRemoteControlManager.handleDown();
expectListToHaveScroll(listElement, -400);
expectButtonToHaveFocus(component, 'button 19');
expectListToHaveScroll(listElement, -700);
expectButtonToHaveFocus(component, 'button 28');
});

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', () => {
Expand All @@ -178,8 +181,6 @@ describe('SpatialNavigationVirtualizedGrid', () => {
renderItem={renderItem}
data={createDataArray(19)}
itemHeight={100}
numberOfRenderedRows={5}
numberOfRowsVisibleOnScreen={3}
numberOfColumns={3}
testID="test-grid"
scrollBehavior="stick-to-end"
Expand Down Expand Up @@ -231,8 +232,6 @@ describe('SpatialNavigationVirtualizedGrid', () => {
renderItem={renderItem}
data={createDataArray(19)}
itemHeight={100}
numberOfRenderedRows={7}
numberOfRowsVisibleOnScreen={3}
numberOfColumns={3}
testID="test-grid"
scrollBehavior="jump-on-scroll"
Expand Down
Loading

0 comments on commit 2268059

Please sign in to comment.