Skip to content

Commit 1c92d56

Browse files
committed
Support reloading pages in infinite list
1 parent 8b3e9a7 commit 1c92d56

File tree

3 files changed

+51
-15
lines changed

3 files changed

+51
-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: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
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';
67

78
import constants from '../commons/constants';
9+
import useCombinedRefs from '../commons/useCombinedRefs';
810

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

@@ -20,12 +22,14 @@ export interface InfiniteListProps
2022
onReachNearEdgeThreshold?: number;
2123
initialPageIndex?: number;
2224
scrollViewProps?: ScrollViewProps;
25+
reloadPages?: (pageIndex: number) => void;
2326
}
2427

2528
const InfiniteList = (props: InfiniteListProps, ref: any) => {
2629
const {
2730
renderItem,
2831
data,
32+
reloadPages,
2933
pageWidth = constants.screenWidth,
3034
pageHeight = constants.screenHeight,
3135
onPageChange,
@@ -50,13 +54,25 @@ const InfiniteList = (props: InfiniteListProps, ref: any) => {
5054
)
5155
);
5256

57+
const listRef = useCombinedRefs(ref);
5358
const pageIndex = useRef<number>();
5459
const isOnEdge = useRef(false);
5560
const isNearEdge = useRef(false);
5661
const scrolledByUser = useRef(false);
5762

63+
// @ts-expect-error lodash can't handle reloadPages signature
64+
const reloadPagesDebounce = useCallback(debounce(reloadPages, 500, {leading: false, trailing: true}), [reloadPages]);
65+
66+
useEffect(() => {
67+
setTimeout(() => {
68+
// @ts-expect-error
69+
listRef.current?.scrollToOffset?.(Math.floor(data.length / 2) * pageWidth, 0, false);
70+
}, 0);
71+
}, [data]);
72+
5873
const onScroll = useCallback(
5974
(event, offsetX, offsetY) => {
75+
reloadPagesDebounce?.cancel();
6076
const newPageIndex = Math.round(event.nativeEvent.contentOffset.x / pageWidth);
6177

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

8298
props.onScroll?.(event, offsetX, offsetY);
8399
},
84-
[props.onScroll, onPageChange, data.length]
100+
[props.onScroll, onPageChange, data.length, reloadPagesDebounce]
85101
);
86102

87103
const onMomentumScrollEnd = useCallback(
88104
event => {
89105
if (isOnEdge.current) {
90106
onReachEdge?.(pageIndex.current!);
107+
reloadPagesDebounce?.(pageIndex.current);
91108
} else if (isNearEdge.current) {
109+
reloadPagesDebounce?.(pageIndex.current);
92110
onReachNearEdge?.(pageIndex.current!);
93111
}
94112

95113
scrollViewProps?.onMomentumScrollEnd?.(event);
96114
},
97-
[scrollViewProps?.onMomentumScrollEnd, onReachEdge, onReachNearEdge]
115+
[scrollViewProps?.onMomentumScrollEnd, onReachEdge, onReachNearEdge, reloadPagesDebounce]
98116
);
99117

100118
const onScrollBeginDrag = useCallback(() => {
@@ -107,7 +125,8 @@ const InfiniteList = (props: InfiniteListProps, ref: any) => {
107125

108126
return (
109127
<RecyclerListView
110-
ref={ref}
128+
// @ts-expect-error
129+
ref={listRef}
111130
isHorizontal
112131
rowRenderer={renderItem}
113132
dataProvider={dataProvider}

0 commit comments

Comments
 (0)