@shopify/flash-list 2.0.0-alpha.15 → 2.0.0-alpha.16
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/dist/recyclerview/RecyclerView.d.ts.map +1 -1
- package/dist/recyclerview/RecyclerView.js +7 -1
- package/dist/recyclerview/RecyclerView.js.map +1 -1
- package/dist/recyclerview/hooks/useLayoutState.d.ts +3 -1
- package/dist/recyclerview/hooks/useLayoutState.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useLayoutState.js +5 -3
- package/dist/recyclerview/hooks/useLayoutState.js.map +1 -1
- package/dist/recyclerview/hooks/useRecyclingState.d.ts +4 -2
- package/dist/recyclerview/hooks/useRecyclingState.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useRecyclingState.js +2 -2
- package/dist/recyclerview/hooks/useRecyclingState.js.map +1 -1
- package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts +9 -1
- package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/GridLayoutManager.js +22 -7
- package/dist/recyclerview/layout-managers/GridLayoutManager.js.map +1 -1
- package/dist/recyclerview/layout-managers/LayoutManager.d.ts +26 -6
- package/dist/recyclerview/layout-managers/LayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/LayoutManager.js +69 -12
- package/dist/recyclerview/layout-managers/LayoutManager.js.map +1 -1
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.d.ts +9 -1
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.js +28 -12
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/viewability/ViewabilityManager.d.ts.map +1 -1
- package/dist/viewability/ViewabilityManager.js +10 -3
- package/dist/viewability/ViewabilityManager.js.map +1 -1
- package/package.json +1 -1
- package/src/recyclerview/RecyclerView.tsx +13 -6
- package/src/recyclerview/hooks/useLayoutState.ts +15 -6
- package/src/recyclerview/hooks/useRecyclingState.ts +11 -7
- package/src/recyclerview/layout-managers/GridLayoutManager.ts +26 -6
- package/src/recyclerview/layout-managers/LayoutManager.ts +74 -15
- package/src/recyclerview/layout-managers/MasonryLayoutManager.ts +30 -8
- package/src/viewability/ViewabilityManager.ts +10 -6
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
2
2
|
|
|
3
|
-
import { useLayoutState } from "./useLayoutState";
|
|
3
|
+
import { LayoutStateSetter, useLayoutState } from "./useLayoutState";
|
|
4
|
+
|
|
5
|
+
export type RecyclingStateSetter<T> = LayoutStateSetter<T>;
|
|
6
|
+
|
|
7
|
+
export type RecyclingStateInitialValue<T> = T | (() => T);
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* A custom hook that provides state management with automatic reset functionality.
|
|
@@ -16,10 +20,10 @@ import { useLayoutState } from "./useLayoutState";
|
|
|
16
20
|
* - A setState function that works like useState's setState
|
|
17
21
|
*/
|
|
18
22
|
export function useRecyclingState<T>(
|
|
19
|
-
initialState: T
|
|
23
|
+
initialState: RecyclingStateInitialValue<T>,
|
|
20
24
|
deps: React.DependencyList,
|
|
21
25
|
onReset?: () => void
|
|
22
|
-
): [T,
|
|
26
|
+
): [T, RecyclingStateSetter<T>] {
|
|
23
27
|
// Store the current state value in a ref to persist between renders
|
|
24
28
|
const valueStore = useRef<T>();
|
|
25
29
|
// Use layoutState to trigger re-renders when state changes
|
|
@@ -42,8 +46,8 @@ export function useRecyclingState<T>(
|
|
|
42
46
|
* Proxy setState function that updates the stored value and triggers a re-render.
|
|
43
47
|
* Only triggers a re-render if the new value is different from the current value.
|
|
44
48
|
*/
|
|
45
|
-
const setStateProxy = useCallback(
|
|
46
|
-
(newValue
|
|
49
|
+
const setStateProxy: RecyclingStateSetter<T> = useCallback(
|
|
50
|
+
(newValue, skipParentLayout) => {
|
|
47
51
|
// Calculate next state value from function or direct value
|
|
48
52
|
const nextState =
|
|
49
53
|
typeof newValue === "function"
|
|
@@ -53,7 +57,7 @@ export function useRecyclingState<T>(
|
|
|
53
57
|
// Only update and trigger re-render if value has changed
|
|
54
58
|
if (nextState !== valueStore.current) {
|
|
55
59
|
valueStore.current = nextState;
|
|
56
|
-
setCounter((prev) => prev + 1);
|
|
60
|
+
setCounter((prev) => prev + 1, skipParentLayout);
|
|
57
61
|
}
|
|
58
62
|
},
|
|
59
63
|
[setCounter]
|
|
@@ -14,6 +14,9 @@ export class RVGridLayoutManagerImpl extends RVLayoutManager {
|
|
|
14
14
|
/** The width of the bounded area for the grid */
|
|
15
15
|
private boundedSize: number;
|
|
16
16
|
|
|
17
|
+
/** If there's a span change for grid layout, we need to recompute all the widths */
|
|
18
|
+
private fullRelayoutRequired = false;
|
|
19
|
+
|
|
17
20
|
constructor(params: LayoutParams, previousLayoutManager?: RVLayoutManager) {
|
|
18
21
|
super(params, previousLayoutManager);
|
|
19
22
|
this.boundedSize = params.windowSize.width;
|
|
@@ -33,10 +36,7 @@ export class RVGridLayoutManagerImpl extends RVLayoutManager {
|
|
|
33
36
|
this.boundedSize = params.windowSize.width;
|
|
34
37
|
if (this.layouts.length > 0) {
|
|
35
38
|
// update all widths
|
|
36
|
-
|
|
37
|
-
this.layouts[i].width = this.getWidth(i);
|
|
38
|
-
}
|
|
39
|
-
// console.log("-----> recomputeLayouts");
|
|
39
|
+
this.updateAllWidths();
|
|
40
40
|
|
|
41
41
|
this.recomputeLayouts(0, this.layouts.length - 1);
|
|
42
42
|
this.requiresRepaint = true;
|
|
@@ -57,6 +57,13 @@ export class RVGridLayoutManagerImpl extends RVLayoutManager {
|
|
|
57
57
|
layout.isHeightMeasured = true;
|
|
58
58
|
layout.isWidthMeasured = true;
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
// TODO: Can be optimized
|
|
62
|
+
if (this.fullRelayoutRequired) {
|
|
63
|
+
this.updateAllWidths();
|
|
64
|
+
this.fullRelayoutRequired = false;
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
/**
|
|
@@ -72,6 +79,14 @@ export class RVGridLayoutManagerImpl extends RVLayoutManager {
|
|
|
72
79
|
layout.enforcedWidth = true;
|
|
73
80
|
}
|
|
74
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Handles span change for an item.
|
|
84
|
+
* @param index Index of the item
|
|
85
|
+
*/
|
|
86
|
+
handleSpanChange(index: number) {
|
|
87
|
+
this.fullRelayoutRequired = true;
|
|
88
|
+
}
|
|
89
|
+
|
|
75
90
|
/**
|
|
76
91
|
* Returns the total size of the layout area.
|
|
77
92
|
* @returns RVDimension containing width and height of the layout
|
|
@@ -122,8 +137,7 @@ export class RVGridLayoutManagerImpl extends RVLayoutManager {
|
|
|
122
137
|
* @returns Width of the item
|
|
123
138
|
*/
|
|
124
139
|
private getWidth(index: number): number {
|
|
125
|
-
|
|
126
|
-
return (this.boundedSize / this.maxColumns) * span;
|
|
140
|
+
return (this.boundedSize / this.maxColumns) * this.getSpan(index);
|
|
127
141
|
}
|
|
128
142
|
|
|
129
143
|
/**
|
|
@@ -205,6 +219,12 @@ export class RVGridLayoutManagerImpl extends RVLayoutManager {
|
|
|
205
219
|
return y + maxHeight;
|
|
206
220
|
}
|
|
207
221
|
|
|
222
|
+
private updateAllWidths() {
|
|
223
|
+
for (let i = 0; i < this.layouts.length; i++) {
|
|
224
|
+
this.layouts[i].width = this.getWidth(i);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
208
228
|
/**
|
|
209
229
|
* Checks if an item can fit within the bounded width.
|
|
210
230
|
* @param itemX Starting X position of the item
|
|
@@ -20,8 +20,6 @@ export abstract class RVLayoutManager {
|
|
|
20
20
|
protected layouts: RVLayout[];
|
|
21
21
|
/** Dimensions of the visible window/viewport */
|
|
22
22
|
protected windowSize: RVDimension;
|
|
23
|
-
/** Information about item spans and sizes */
|
|
24
|
-
protected spanSizeInfo: SpanSizeInfo = {};
|
|
25
23
|
/** Maximum number of columns in the layout */
|
|
26
24
|
protected maxColumns: number;
|
|
27
25
|
|
|
@@ -41,6 +39,13 @@ export abstract class RVLayoutManager {
|
|
|
41
39
|
private widthAverageWindow: MultiTypeAverageWindow;
|
|
42
40
|
/** Maximum number of items to process in a single layout pass */
|
|
43
41
|
private maxItemsToProcess = 250; // TODO: make this dynamic
|
|
42
|
+
/** Information about item spans and sizes */
|
|
43
|
+
private spanSizeInfo: SpanSizeInfo = {};
|
|
44
|
+
/** Span tracker for each item */
|
|
45
|
+
private spanTracker: (number | undefined)[] = [];
|
|
46
|
+
|
|
47
|
+
/** Current max index with changed layout */
|
|
48
|
+
private currentMaxIndexWithChangedLayout = -1;
|
|
44
49
|
|
|
45
50
|
constructor(params: LayoutParams, previousLayoutManager?: RVLayoutManager) {
|
|
46
51
|
this.heightAverageWindow = new MultiTypeAverageWindow(5, 200);
|
|
@@ -164,37 +169,46 @@ export abstract class RVLayoutManager {
|
|
|
164
169
|
|
|
165
170
|
if (this.layouts.length > totalItemCount) {
|
|
166
171
|
this.layouts.length = totalItemCount;
|
|
172
|
+
this.spanTracker.length = totalItemCount;
|
|
167
173
|
minRecomputeIndex = totalItemCount - 1; // <0 gets skipped so it's safe to set to totalItemCount - 1
|
|
168
174
|
}
|
|
169
175
|
// update average windows
|
|
170
176
|
minRecomputeIndex = Math.min(
|
|
171
177
|
minRecomputeIndex,
|
|
172
|
-
this.
|
|
178
|
+
this.computeEstimatesAndMinMaxChangedLayout(layoutInfo)
|
|
173
179
|
);
|
|
174
180
|
|
|
175
181
|
if (this.layouts.length < totalItemCount && totalItemCount > 0) {
|
|
176
182
|
const startIndex = this.layouts.length;
|
|
177
183
|
this.layouts.length = totalItemCount;
|
|
184
|
+
this.spanTracker.length = totalItemCount;
|
|
178
185
|
for (let i = startIndex; i < totalItemCount; i++) {
|
|
179
186
|
this.getLayout(i);
|
|
187
|
+
this.getSpan(i);
|
|
180
188
|
}
|
|
181
189
|
this.recomputeLayouts(startIndex, totalItemCount - 1);
|
|
182
190
|
}
|
|
183
|
-
|
|
184
|
-
minRecomputeIndex,
|
|
185
|
-
this.processLayoutInfo(layoutInfo, totalItemCount) ?? minRecomputeIndex
|
|
186
|
-
);
|
|
191
|
+
|
|
187
192
|
// compute minRecomputeIndex
|
|
193
|
+
|
|
188
194
|
minRecomputeIndex = Math.min(
|
|
189
195
|
minRecomputeIndex,
|
|
190
|
-
this.
|
|
196
|
+
this.computeMinIndexWithChangedSpan(layoutInfo),
|
|
197
|
+
this.processLayoutInfo(layoutInfo, totalItemCount) ?? minRecomputeIndex,
|
|
198
|
+
this.computeEstimatesAndMinMaxChangedLayout(layoutInfo)
|
|
191
199
|
);
|
|
200
|
+
|
|
192
201
|
if (minRecomputeIndex >= 0 && minRecomputeIndex < totalItemCount) {
|
|
202
|
+
const maxRecomputeIndex = this.getMaxRecomputeIndex(minRecomputeIndex);
|
|
193
203
|
this.recomputeLayouts(
|
|
194
204
|
this.getMinRecomputeIndex(minRecomputeIndex),
|
|
195
|
-
|
|
205
|
+
maxRecomputeIndex
|
|
196
206
|
);
|
|
207
|
+
if (maxRecomputeIndex + 1 < totalItemCount) {
|
|
208
|
+
this.layouts[maxRecomputeIndex + 1].repositionPending = true;
|
|
209
|
+
}
|
|
197
210
|
}
|
|
211
|
+
this.currentMaxIndexWithChangedLayout = -1;
|
|
198
212
|
}
|
|
199
213
|
|
|
200
214
|
/**
|
|
@@ -260,16 +274,30 @@ export abstract class RVLayoutManager {
|
|
|
260
274
|
protected abstract estimateLayout(index: number): void;
|
|
261
275
|
|
|
262
276
|
/**
|
|
263
|
-
* Gets span
|
|
277
|
+
* Gets span for an item, applying any overrides.
|
|
278
|
+
* This is intended to be called during a relayout call. The value is tracked and used to determine if a span change has occurred.
|
|
279
|
+
* If skipTracking is true, the operation is not tracked. Can be useful if span is required outside of a relayout call.
|
|
280
|
+
* The tracker is used to call handleSpanChange if a span change has occurred before relayout call.
|
|
281
|
+
* // TODO: improve this contract.
|
|
264
282
|
* @param index Index of the item
|
|
265
|
-
* @returns
|
|
283
|
+
* @returns Span for the item
|
|
266
284
|
*/
|
|
267
|
-
protected
|
|
285
|
+
protected getSpan(index: number, skipTracking = false): number {
|
|
268
286
|
this.spanSizeInfo.span = undefined;
|
|
269
287
|
this.overrideItemLayout(index, this.spanSizeInfo);
|
|
270
|
-
|
|
288
|
+
const span = Math.min(this.spanSizeInfo.span ?? 1, this.maxColumns);
|
|
289
|
+
if (!skipTracking) {
|
|
290
|
+
this.spanTracker[index] = span;
|
|
291
|
+
}
|
|
292
|
+
return span;
|
|
271
293
|
}
|
|
272
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Method to handle span change for an item. Can be overridden by subclasses.
|
|
297
|
+
* @param index Index of the item
|
|
298
|
+
*/
|
|
299
|
+
protected handleSpanChange(index: number) {}
|
|
300
|
+
|
|
273
301
|
/**
|
|
274
302
|
* Gets the maximum index to process in a single layout pass.
|
|
275
303
|
* @param startIndex Starting index
|
|
@@ -277,7 +305,8 @@ export abstract class RVLayoutManager {
|
|
|
277
305
|
*/
|
|
278
306
|
private getMaxRecomputeIndex(startIndex: number): number {
|
|
279
307
|
return Math.min(
|
|
280
|
-
startIndex
|
|
308
|
+
Math.max(startIndex, this.currentMaxIndexWithChangedLayout) +
|
|
309
|
+
this.maxItemsToProcess,
|
|
281
310
|
this.layouts.length - 1
|
|
282
311
|
);
|
|
283
312
|
}
|
|
@@ -296,7 +325,7 @@ export abstract class RVLayoutManager {
|
|
|
296
325
|
* @param layoutInfo Array of layout information for items
|
|
297
326
|
* @returns Minimum index that needs recomputation
|
|
298
327
|
*/
|
|
299
|
-
private
|
|
328
|
+
private computeEstimatesAndMinMaxChangedLayout(
|
|
300
329
|
layoutInfo: RVLayoutInfo[]
|
|
301
330
|
): number {
|
|
302
331
|
let minRecomputeIndex = Number.MAX_VALUE;
|
|
@@ -307,10 +336,18 @@ export abstract class RVLayoutManager {
|
|
|
307
336
|
!storedLayout ||
|
|
308
337
|
!storedLayout.isHeightMeasured ||
|
|
309
338
|
!storedLayout.isWidthMeasured ||
|
|
339
|
+
storedLayout.repositionPending ||
|
|
310
340
|
areDimensionsNotEqual(storedLayout.height, dimensions.height) ||
|
|
311
341
|
areDimensionsNotEqual(storedLayout.width, dimensions.width)
|
|
312
342
|
) {
|
|
313
343
|
minRecomputeIndex = Math.min(minRecomputeIndex, index);
|
|
344
|
+
this.currentMaxIndexWithChangedLayout = Math.max(
|
|
345
|
+
this.currentMaxIndexWithChangedLayout,
|
|
346
|
+
index
|
|
347
|
+
);
|
|
348
|
+
if (storedLayout?.repositionPending) {
|
|
349
|
+
storedLayout.repositionPending = false;
|
|
350
|
+
}
|
|
314
351
|
}
|
|
315
352
|
this.heightAverageWindow.addValue(
|
|
316
353
|
dimensions.height,
|
|
@@ -323,6 +360,21 @@ export abstract class RVLayoutManager {
|
|
|
323
360
|
}
|
|
324
361
|
return minRecomputeIndex;
|
|
325
362
|
}
|
|
363
|
+
|
|
364
|
+
private computeMinIndexWithChangedSpan(layoutInfo: RVLayoutInfo[]): number {
|
|
365
|
+
let minIndexWithChangedSpan = Number.MAX_VALUE;
|
|
366
|
+
for (const info of layoutInfo) {
|
|
367
|
+
const { index } = info;
|
|
368
|
+
const span = this.getSpan(index, true);
|
|
369
|
+
const storedSpan = this.spanTracker[index];
|
|
370
|
+
if (span !== storedSpan) {
|
|
371
|
+
this.spanTracker[index] = span;
|
|
372
|
+
this.handleSpanChange(index);
|
|
373
|
+
minIndexWithChangedSpan = Math.min(minIndexWithChangedSpan, index);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return minIndexWithChangedSpan;
|
|
377
|
+
}
|
|
326
378
|
}
|
|
327
379
|
|
|
328
380
|
/**
|
|
@@ -467,6 +519,13 @@ export interface RVLayout extends RVDimension {
|
|
|
467
519
|
* When false, the height is determined by content
|
|
468
520
|
*/
|
|
469
521
|
enforcedHeight?: boolean;
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* When true, the layout is pending repositioning
|
|
525
|
+
* When false, the layout is up to date
|
|
526
|
+
* ViewHolder update is not required.
|
|
527
|
+
*/
|
|
528
|
+
repositionPending?: boolean;
|
|
470
529
|
}
|
|
471
530
|
|
|
472
531
|
/**
|
|
@@ -19,10 +19,13 @@ export class RVMasonryLayoutManagerImpl extends RVLayoutManager {
|
|
|
19
19
|
/** Current column index for sequential placement */
|
|
20
20
|
private currentColumn = 0;
|
|
21
21
|
|
|
22
|
+
/** If there's a span change for masonry layout, we need to recompute all the widths */
|
|
23
|
+
private fullRelayoutRequired = false;
|
|
24
|
+
|
|
22
25
|
constructor(params: LayoutParams, previousLayoutManager?: RVLayoutManager) {
|
|
23
26
|
super(params, previousLayoutManager);
|
|
24
27
|
this.boundedSize = params.windowSize.width;
|
|
25
|
-
this.optimizeItemArrangement = params.optimizeItemArrangement
|
|
28
|
+
this.optimizeItemArrangement = params.optimizeItemArrangement;
|
|
26
29
|
this.columnHeights = this.columnHeights ?? Array(this.maxColumns).fill(0);
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -44,10 +47,7 @@ export class RVMasonryLayoutManagerImpl extends RVLayoutManager {
|
|
|
44
47
|
// console.log("-----> recomputeLayouts");
|
|
45
48
|
|
|
46
49
|
// update all widths
|
|
47
|
-
|
|
48
|
-
this.layouts[i].width = this.getWidth(i);
|
|
49
|
-
this.layouts[i].minHeight = undefined;
|
|
50
|
-
}
|
|
50
|
+
this.updateAllWidths();
|
|
51
51
|
this.recomputeLayouts(0, this.layouts.length - 1);
|
|
52
52
|
this.requiresRepaint = true;
|
|
53
53
|
}
|
|
@@ -69,6 +69,13 @@ export class RVMasonryLayoutManagerImpl extends RVLayoutManager {
|
|
|
69
69
|
layout.isWidthMeasured = true;
|
|
70
70
|
this.layouts[index] = layout;
|
|
71
71
|
}
|
|
72
|
+
|
|
73
|
+
// TODO: Can be optimized
|
|
74
|
+
if (this.fullRelayoutRequired) {
|
|
75
|
+
this.updateAllWidths();
|
|
76
|
+
this.fullRelayoutRequired = false;
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
/**
|
|
@@ -87,6 +94,14 @@ export class RVMasonryLayoutManagerImpl extends RVLayoutManager {
|
|
|
87
94
|
layout.enforcedWidth = true;
|
|
88
95
|
}
|
|
89
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Handles span change for an item.
|
|
99
|
+
* @param index Index of the item
|
|
100
|
+
*/
|
|
101
|
+
handleSpanChange(index: number) {
|
|
102
|
+
this.fullRelayoutRequired = true;
|
|
103
|
+
}
|
|
104
|
+
|
|
90
105
|
/**
|
|
91
106
|
* Returns the total size of the layout area.
|
|
92
107
|
* @returns RVDimension containing width and height of the layout
|
|
@@ -124,7 +139,8 @@ export class RVMasonryLayoutManagerImpl extends RVLayoutManager {
|
|
|
124
139
|
|
|
125
140
|
for (let i = startIndex; i < itemCount; i++) {
|
|
126
141
|
const layout = this.getLayout(i);
|
|
127
|
-
|
|
142
|
+
// Skip tracking span because we're not changing widths
|
|
143
|
+
const span = this.getSpan(i, true);
|
|
128
144
|
|
|
129
145
|
if (this.optimizeItemArrangement) {
|
|
130
146
|
if (span === 1) {
|
|
@@ -147,8 +163,14 @@ export class RVMasonryLayoutManagerImpl extends RVLayoutManager {
|
|
|
147
163
|
* @returns Width of the item
|
|
148
164
|
*/
|
|
149
165
|
private getWidth(index: number): number {
|
|
150
|
-
|
|
151
|
-
|
|
166
|
+
return (this.boundedSize / this.maxColumns) * this.getSpan(index);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private updateAllWidths() {
|
|
170
|
+
for (let i = 0; i < this.layouts.length; i++) {
|
|
171
|
+
this.layouts[i].width = this.getWidth(i);
|
|
172
|
+
this.layouts[i].minHeight = undefined;
|
|
173
|
+
}
|
|
152
174
|
}
|
|
153
175
|
|
|
154
176
|
/**
|
|
@@ -22,17 +22,21 @@ export default class ViewabilityManager<T> {
|
|
|
22
22
|
this.viewabilityHelpers.push(
|
|
23
23
|
this.createViewabilityHelper(
|
|
24
24
|
flashListRef.props.viewabilityConfig,
|
|
25
|
-
|
|
25
|
+
(info) => {
|
|
26
|
+
flashListRef.props.onViewableItemsChanged?.(info);
|
|
27
|
+
}
|
|
26
28
|
)
|
|
27
29
|
);
|
|
28
30
|
}
|
|
29
31
|
(flashListRef.props.viewabilityConfigCallbackPairs ?? []).forEach(
|
|
30
|
-
(pair) => {
|
|
32
|
+
(pair, index) => {
|
|
31
33
|
this.viewabilityHelpers.push(
|
|
32
|
-
this.createViewabilityHelper(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
this.createViewabilityHelper(pair.viewabilityConfig, (info) => {
|
|
35
|
+
const callback =
|
|
36
|
+
flashListRef.props.viewabilityConfigCallbackPairs?.[index]
|
|
37
|
+
?.onViewableItemsChanged;
|
|
38
|
+
callback?.(info);
|
|
39
|
+
})
|
|
36
40
|
);
|
|
37
41
|
}
|
|
38
42
|
);
|