Skip to content

Commit 43c7174

Browse files
authored
Merge pull request #1810 from wix/feat/improveInfiniteList
Feat/improve infinite list
2 parents 8b3e9a7 + 71f8ead commit 43c7174

File tree

3 files changed

+50
-15
lines changed

3 files changed

+50
-15
lines changed

src/commons/useCombinedRefs.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
3+
const useCombinedRefs = (...refs: React.Ref<any>[]) => {
4+
const targetRef = React.useRef();
5+
6+
React.useEffect(() => {
7+
refs.forEach(ref => {
8+
if (!ref) {
9+
return;
10+
}
11+
12+
if (typeof ref === 'function') {
13+
ref(targetRef.current);
14+
} else {
15+
// @ts-expect-error
16+
ref.current = targetRef.current;
17+
}
18+
});
19+
}, [refs]);
20+
21+
return targetRef;
22+
};
23+
24+
export default useCombinedRefs;

src/expandableCalendar/WeekCalendar/new.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@ const WeekCalendar = (props: WeekCalendarProps) => {
4343
return [{width: containerWidth}, props.style];
4444
}, [containerWidth, props.style]);
4545

46-
// NOTE: Responsible for sync scroll position after reloading new items
47-
useEffect(() => {
48-
setTimeout(() => {
49-
// @ts-expect-error
50-
list.current?.scrollToOffset?.(NUMBER_OF_PAGES * containerWidth, 0, false);
51-
}, 0);
52-
}, [items]);
53-
5446
useEffect(() => {
5547
if (updateSource !== UpdateSources.WEEK_SCROLL) {
5648
const pageIndex = items.findIndex(item => sameWeek(item, date, firstDay));
@@ -76,12 +68,12 @@ const WeekCalendar = (props: WeekCalendarProps) => {
7668
[items]
7769
);
7870

79-
const onReachEdge = useCallback(
71+
const reloadPages = useCallback(
8072
pageIndex => {
8173
const date = items[pageIndex];
8274
setItems(getDatesArray(date, firstDay, NUMBER_OF_PAGES));
8375
},
84-
[items, containerWidth]
76+
[items]
8577
);
8678

8779
const renderItem = useCallback(
@@ -123,13 +115,14 @@ const WeekCalendar = (props: WeekCalendarProps) => {
123115
ref={list}
124116
data={items}
125117
renderItem={renderItem}
118+
reloadPages={reloadPages}
119+
onReachNearEdgeThreshold={Math.round(NUMBER_OF_PAGES * 0.4)}
126120
extendedState={extraData}
127121
style={style.current.container}
128122
initialPageIndex={NUMBER_OF_PAGES}
129123
pageHeight={48}
130124
pageWidth={containerWidth}
131125
onPageChange={onPageChange}
132-
onReachEdge={onReachEdge}
133126
scrollViewProps={{
134127
showsHorizontalScrollIndicator: false
135128
}}

src/infinite-list/index.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
// TODO: Make this a common component for all horizontal lists in this lib
2-
import React, {forwardRef, useCallback, useMemo, useRef} from 'react';
2+
import React, {forwardRef, useCallback, useEffect, useMemo, useRef} from 'react';
33
import {ScrollViewProps} from 'react-native';
44
import {DataProvider, LayoutProvider, RecyclerListView, RecyclerListViewProps} from 'recyclerlistview';
55
import inRange from 'lodash/inRange';
6+
import debounce from 'lodash/debounce';
7+
import noop from 'lodash/noop';
68

79
import constants from '../commons/constants';
10+
import useCombinedRefs from '../commons/useCombinedRefs';
811

912
const dataProviderMaker = (items: string[]) => new DataProvider((item1, item2) => item1 !== item2).cloneWithRows(items);
1013

@@ -20,12 +23,14 @@ export interface InfiniteListProps
2023
onReachNearEdgeThreshold?: number;
2124
initialPageIndex?: number;
2225
scrollViewProps?: ScrollViewProps;
26+
reloadPages?: (pageIndex: number) => void;
2327
}
2428

2529
const InfiniteList = (props: InfiniteListProps, ref: any) => {
2630
const {
2731
renderItem,
2832
data,
33+
reloadPages = noop,
2934
pageWidth = constants.screenWidth,
3035
pageHeight = constants.screenHeight,
3136
onPageChange,
@@ -50,13 +55,23 @@ const InfiniteList = (props: InfiniteListProps, ref: any) => {
5055
)
5156
);
5257

58+
const listRef = useCombinedRefs(ref);
5359
const pageIndex = useRef<number>();
5460
const isOnEdge = useRef(false);
5561
const isNearEdge = useRef(false);
5662
const scrolledByUser = useRef(false);
63+
const reloadPagesDebounce = useCallback(debounce(reloadPages, 500, {leading: false, trailing: true}), [reloadPages]);
64+
65+
useEffect(() => {
66+
setTimeout(() => {
67+
// @ts-expect-error
68+
listRef.current?.scrollToOffset?.(Math.floor(data.length / 2) * pageWidth, 0, false);
69+
}, 0);
70+
}, [data]);
5771

5872
const onScroll = useCallback(
5973
(event, offsetX, offsetY) => {
74+
reloadPagesDebounce?.cancel();
6075
const newPageIndex = Math.round(event.nativeEvent.contentOffset.x / pageWidth);
6176

6277
if (pageIndex.current !== newPageIndex) {
@@ -81,20 +96,22 @@ const InfiniteList = (props: InfiniteListProps, ref: any) => {
8196

8297
props.onScroll?.(event, offsetX, offsetY);
8398
},
84-
[props.onScroll, onPageChange, data.length]
99+
[props.onScroll, onPageChange, data.length, reloadPagesDebounce]
85100
);
86101

87102
const onMomentumScrollEnd = useCallback(
88103
event => {
89104
if (isOnEdge.current) {
90105
onReachEdge?.(pageIndex.current!);
106+
reloadPagesDebounce?.(pageIndex.current);
91107
} else if (isNearEdge.current) {
108+
reloadPagesDebounce?.(pageIndex.current);
92109
onReachNearEdge?.(pageIndex.current!);
93110
}
94111

95112
scrollViewProps?.onMomentumScrollEnd?.(event);
96113
},
97-
[scrollViewProps?.onMomentumScrollEnd, onReachEdge, onReachNearEdge]
114+
[scrollViewProps?.onMomentumScrollEnd, onReachEdge, onReachNearEdge, reloadPagesDebounce]
98115
);
99116

100117
const onScrollBeginDrag = useCallback(() => {
@@ -107,7 +124,8 @@ const InfiniteList = (props: InfiniteListProps, ref: any) => {
107124

108125
return (
109126
<RecyclerListView
110-
ref={ref}
127+
// @ts-expect-error
128+
ref={listRef}
111129
isHorizontal
112130
rowRenderer={renderItem}
113131
dataProvider={dataProvider}

0 commit comments

Comments
 (0)