@shopify/flash-list 2.0.0-alpha.10 → 2.0.0-alpha.11

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.
Files changed (119) hide show
  1. package/README.md +6 -2
  2. package/dist/AnimatedFlashList.d.ts.map +1 -1
  3. package/dist/AnimatedFlashList.js +3 -3
  4. package/dist/AnimatedFlashList.js.map +1 -1
  5. package/dist/FlashList.d.ts +9 -0
  6. package/dist/FlashList.d.ts.map +1 -1
  7. package/dist/FlashList.js +20 -0
  8. package/dist/FlashList.js.map +1 -1
  9. package/dist/FlashListProps.d.ts +13 -6
  10. package/dist/FlashListProps.d.ts.map +1 -1
  11. package/dist/FlashListProps.js.map +1 -1
  12. package/dist/FlashListRef.d.ts +295 -0
  13. package/dist/FlashListRef.d.ts.map +1 -0
  14. package/dist/FlashListRef.js +3 -0
  15. package/dist/FlashListRef.js.map +1 -0
  16. package/dist/__tests__/RecyclerView.test.js +62 -27
  17. package/dist/__tests__/RecyclerView.test.js.map +1 -1
  18. package/dist/__tests__/RenderStackManager.test.d.ts +2 -0
  19. package/dist/__tests__/RenderStackManager.test.d.ts.map +1 -0
  20. package/dist/__tests__/RenderStackManager.test.js +405 -0
  21. package/dist/__tests__/RenderStackManager.test.js.map +1 -0
  22. package/dist/__tests__/useUnmountAwareCallbacks.test.js +1 -1
  23. package/dist/__tests__/useUnmountAwareCallbacks.test.js.map +1 -1
  24. package/dist/benchmark/useFlatListBenchmark.js +8 -7
  25. package/dist/benchmark/useFlatListBenchmark.js.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/recyclerview/RecyclerView.d.ts +2 -1
  30. package/dist/recyclerview/RecyclerView.d.ts.map +1 -1
  31. package/dist/recyclerview/RecyclerView.js +33 -14
  32. package/dist/recyclerview/RecyclerView.js.map +1 -1
  33. package/dist/recyclerview/RecyclerViewContextProvider.d.ts +6 -5
  34. package/dist/recyclerview/RecyclerViewContextProvider.d.ts.map +1 -1
  35. package/dist/recyclerview/RecyclerViewContextProvider.js.map +1 -1
  36. package/dist/recyclerview/RecyclerViewManager.d.ts +11 -7
  37. package/dist/recyclerview/RecyclerViewManager.d.ts.map +1 -1
  38. package/dist/recyclerview/RecyclerViewManager.js +57 -102
  39. package/dist/recyclerview/RecyclerViewManager.js.map +1 -1
  40. package/dist/recyclerview/RenderStackManager.d.ts +85 -0
  41. package/dist/recyclerview/RenderStackManager.d.ts.map +1 -0
  42. package/dist/recyclerview/RenderStackManager.js +261 -0
  43. package/dist/recyclerview/RenderStackManager.js.map +1 -0
  44. package/dist/recyclerview/ViewHolder.d.ts.map +1 -1
  45. package/dist/recyclerview/ViewHolder.js +5 -3
  46. package/dist/recyclerview/ViewHolder.js.map +1 -1
  47. package/dist/recyclerview/ViewHolderCollection.d.ts +3 -1
  48. package/dist/recyclerview/ViewHolderCollection.d.ts.map +1 -1
  49. package/dist/recyclerview/ViewHolderCollection.js +19 -3
  50. package/dist/recyclerview/ViewHolderCollection.js.map +1 -1
  51. package/dist/recyclerview/components/ScrollAnchor.d.ts.map +1 -1
  52. package/dist/recyclerview/components/ScrollAnchor.js +1 -1
  53. package/dist/recyclerview/components/ScrollAnchor.js.map +1 -1
  54. package/dist/recyclerview/components/StickyHeaders.d.ts.map +1 -1
  55. package/dist/recyclerview/components/StickyHeaders.js +44 -17
  56. package/dist/recyclerview/components/StickyHeaders.js.map +1 -1
  57. package/dist/recyclerview/hooks/useBoundDetection.d.ts +1 -2
  58. package/dist/recyclerview/hooks/useBoundDetection.d.ts.map +1 -1
  59. package/dist/recyclerview/hooks/useBoundDetection.js +19 -16
  60. package/dist/recyclerview/hooks/useBoundDetection.js.map +1 -1
  61. package/dist/recyclerview/hooks/useOnLoad.d.ts.map +1 -1
  62. package/dist/recyclerview/hooks/useOnLoad.js +4 -6
  63. package/dist/recyclerview/hooks/useOnLoad.js.map +1 -1
  64. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts +3 -48
  65. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts.map +1 -1
  66. package/dist/recyclerview/hooks/useRecyclerViewController.js +93 -71
  67. package/dist/recyclerview/hooks/useRecyclerViewController.js.map +1 -1
  68. package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts.map +1 -1
  69. package/dist/recyclerview/hooks/useRecyclerViewManager.js +6 -0
  70. package/dist/recyclerview/hooks/useRecyclerViewManager.js.map +1 -1
  71. package/dist/recyclerview/hooks/useSecondaryProps.js +1 -1
  72. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts +10 -3
  73. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts.map +1 -1
  74. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js +33 -4
  75. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js.map +1 -1
  76. package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts +6 -0
  77. package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts.map +1 -1
  78. package/dist/recyclerview/layout-managers/GridLayoutManager.js +27 -5
  79. package/dist/recyclerview/layout-managers/GridLayoutManager.js.map +1 -1
  80. package/dist/recyclerview/layout-managers/LayoutManager.d.ts +2 -2
  81. package/dist/recyclerview/layout-managers/LayoutManager.js +2 -2
  82. package/dist/tsconfig.tsbuildinfo +1 -1
  83. package/jestSetup.js +30 -11
  84. package/package.json +1 -1
  85. package/src/AnimatedFlashList.ts +3 -2
  86. package/src/FlashList.tsx +24 -0
  87. package/src/FlashListProps.ts +16 -7
  88. package/src/FlashListRef.ts +309 -0
  89. package/src/__tests__/RecyclerView.test.tsx +83 -29
  90. package/src/__tests__/RenderStackManager.test.ts +488 -0
  91. package/src/__tests__/useUnmountAwareCallbacks.test.tsx +12 -12
  92. package/src/benchmark/useFlatListBenchmark.ts +2 -2
  93. package/src/index.ts +1 -0
  94. package/src/recyclerview/RecyclerView.tsx +38 -23
  95. package/src/recyclerview/RecyclerViewContextProvider.ts +12 -6
  96. package/src/recyclerview/RecyclerViewManager.ts +73 -88
  97. package/src/recyclerview/RenderStackManager.ts +265 -0
  98. package/src/recyclerview/ViewHolder.tsx +5 -3
  99. package/src/recyclerview/ViewHolderCollection.tsx +29 -8
  100. package/src/recyclerview/components/ScrollAnchor.tsx +9 -5
  101. package/src/recyclerview/components/StickyHeaders.tsx +57 -19
  102. package/src/recyclerview/hooks/useBoundDetection.ts +25 -18
  103. package/src/recyclerview/hooks/useOnLoad.ts +4 -6
  104. package/src/recyclerview/hooks/useRecyclerViewController.tsx +104 -125
  105. package/src/recyclerview/hooks/useRecyclerViewManager.ts +6 -0
  106. package/src/recyclerview/hooks/useSecondaryProps.tsx +1 -1
  107. package/src/recyclerview/hooks/useUnmountAwareCallbacks.ts +39 -3
  108. package/src/recyclerview/layout-managers/GridLayoutManager.ts +30 -7
  109. package/src/recyclerview/layout-managers/LayoutManager.ts +2 -2
  110. package/dist/__tests__/RecycleKeyManager.test.d.ts +0 -2
  111. package/dist/__tests__/RecycleKeyManager.test.d.ts.map +0 -1
  112. package/dist/__tests__/RecycleKeyManager.test.js +0 -210
  113. package/dist/__tests__/RecycleKeyManager.test.js.map +0 -1
  114. package/dist/recyclerview/RecycleKeyManager.d.ts +0 -82
  115. package/dist/recyclerview/RecycleKeyManager.d.ts.map +0 -1
  116. package/dist/recyclerview/RecycleKeyManager.js +0 -135
  117. package/dist/recyclerview/RecycleKeyManager.js.map +0 -1
  118. package/src/__tests__/RecycleKeyManager.test.ts +0 -254
  119. package/src/recyclerview/RecycleKeyManager.ts +0 -185
@@ -19,6 +19,8 @@ import {
19
19
  NativeSyntheticEvent,
20
20
  } from "react-native";
21
21
 
22
+ import { FlashListRef } from "../FlashListRef";
23
+
22
24
  import { RVDimension } from "./layout-managers/LayoutManager";
23
25
  import {
24
26
  areDimensionsNotEqual,
@@ -55,7 +57,7 @@ import { RenderTimeTracker } from "./helpers/RenderTimeTracker";
55
57
  */
56
58
  const RecyclerViewComponent = <T,>(
57
59
  props: RecyclerViewProps<T>,
58
- ref: React.Ref<any>
60
+ ref: React.Ref<FlashListRef<T>>
59
61
  ) => {
60
62
  // Destructure props and initialize refs
61
63
  const {
@@ -76,8 +78,6 @@ const RecyclerViewComponent = <T,>(
76
78
  ListFooterComponentStyle,
77
79
  ItemSeparatorComponent,
78
80
  renderScrollComponent,
79
- onScroll,
80
- disableRecycling,
81
81
  style,
82
82
  stickyHeaderIndices,
83
83
  maintainVisibleContentPosition,
@@ -116,13 +116,12 @@ const RecyclerViewComponent = <T,>(
116
116
  // Initialize core RecyclerView manager and content offset management
117
117
  const { recyclerViewManager, velocityTracker } =
118
118
  useRecyclerViewManager(props);
119
- const { applyContentOffset, applyInitialScrollIndex } =
119
+ const { applyContentOffset, applyInitialScrollIndex, handlerMethods } =
120
120
  useRecyclerViewController(
121
121
  recyclerViewManager,
122
122
  ref,
123
123
  scrollViewRef,
124
- scrollAnchorRef,
125
- props
124
+ scrollAnchorRef
126
125
  );
127
126
 
128
127
  // Initialize view holder collection ref
@@ -132,11 +131,7 @@ const RecyclerViewComponent = <T,>(
132
131
  useOnListLoad(recyclerViewManager, onLoad);
133
132
 
134
133
  // Hook to detect when scrolling reaches list bounds
135
- const { checkBounds } = useBoundDetection(
136
- recyclerViewManager,
137
- props,
138
- scrollViewRef
139
- );
134
+ const { checkBounds } = useBoundDetection(recyclerViewManager, scrollViewRef);
140
135
 
141
136
  const isHorizontalRTL = I18nManager.isRTL && horizontal;
142
137
 
@@ -182,6 +177,7 @@ const RecyclerViewComponent = <T,>(
182
177
  * Effect to handle layout updates for list items
183
178
  * This ensures proper positioning and recycling of items
184
179
  */
180
+ // eslint-disable-next-line react-hooks/exhaustive-deps
185
181
  useLayoutEffect(() => {
186
182
  if (pendingChildIds.size > 0) {
187
183
  return;
@@ -272,22 +268,31 @@ const RecyclerViewComponent = <T,>(
272
268
  recyclerViewManager.computeItemViewability();
273
269
 
274
270
  // Call user-provided onScroll handler
275
- onScroll?.(event);
271
+ recyclerViewManager.props.onScroll?.(event);
276
272
  },
277
- [horizontal, isHorizontalRTL, recyclerViewManager]
273
+ [
274
+ checkBounds,
275
+ horizontal,
276
+ isHorizontalRTL,
277
+ recyclerViewManager,
278
+ velocityTracker,
279
+ ]
278
280
  );
279
281
 
280
282
  // Create context for child components
281
- const recyclerViewContext: RecyclerViewContext = useMemo(() => {
283
+ const recyclerViewContext: RecyclerViewContext<T> = useMemo(() => {
282
284
  return {
283
285
  layout: () => {
284
286
  setLayoutTreeId((prev) => prev + 1);
285
287
  },
286
288
  getRef: () => {
287
- return ref;
289
+ if (recyclerViewManager.isDisposed) {
290
+ return null;
291
+ }
292
+ return handlerMethods;
288
293
  },
289
294
  getScrollViewRef: () => {
290
- return scrollViewRef;
295
+ return scrollViewRef.current;
291
296
  },
292
297
  markChildLayoutAsPending: (id: string) => {
293
298
  pendingChildIds.add(id);
@@ -299,7 +304,7 @@ const RecyclerViewComponent = <T,>(
299
304
  }
300
305
  },
301
306
  };
302
- }, [setLayoutTreeId]);
307
+ }, [handlerMethods, pendingChildIds, recyclerViewManager, setLayoutTreeId]);
303
308
 
304
309
  const parentRecyclerViewContext = useRecyclerViewContext();
305
310
  const recyclerViewId = useId();
@@ -334,7 +339,7 @@ const RecyclerViewComponent = <T,>(
334
339
  recyclerViewContext.layout();
335
340
  }
336
341
  },
337
- [recyclerViewManager]
342
+ [recyclerViewContext, recyclerViewManager]
338
343
  );
339
344
 
340
345
  // Get secondary props and components
@@ -374,7 +379,14 @@ const RecyclerViewComponent = <T,>(
374
379
  );
375
380
  }
376
381
  return null;
377
- }, [data, stickyHeaderIndices, renderItem, extraData]);
382
+ }, [
383
+ data,
384
+ stickyHeaderIndices,
385
+ renderItem,
386
+ scrollY,
387
+ recyclerViewManager,
388
+ extraData,
389
+ ]);
378
390
 
379
391
  // Set up scroll event handling with animation support for sticky headers
380
392
  const animatedEvent = useMemo(() => {
@@ -385,7 +397,7 @@ const RecyclerViewComponent = <T,>(
385
397
  );
386
398
  }
387
399
  return onScrollHandler;
388
- }, [onScrollHandler, stickyHeaders]);
400
+ }, [onScrollHandler, scrollY, stickyHeaders]);
389
401
 
390
402
  const maintainVisibleContentPositionInternal = useMemo(() => {
391
403
  if (maintainVisibleContentPosition?.disabled || horizontal) {
@@ -396,7 +408,7 @@ const RecyclerViewComponent = <T,>(
396
408
  minIndexForVisible: 0,
397
409
  };
398
410
  }
399
- }, [maintainVisibleContentPosition]);
411
+ }, [horizontal, maintainVisibleContentPosition]);
400
412
 
401
413
  const shouldRenderFromBottom =
402
414
  maintainVisibleContentPositionInternal?.startRenderingFromBottom ?? false;
@@ -503,7 +515,7 @@ const RecyclerViewComponent = <T,>(
503
515
  applyInitialScrollIndex();
504
516
  checkBounds();
505
517
  recyclerViewManager.computeItemViewability();
506
- recyclerViewManager.disableRecycling = Boolean(disableRecycling);
518
+ recyclerViewManager.disableRecycling(false);
507
519
  }}
508
520
  CellRendererComponent={CellRendererComponent}
509
521
  ItemSeparatorComponent={ItemSeparatorComponent}
@@ -522,9 +534,12 @@ const RecyclerViewComponent = <T,>(
522
534
  );
523
535
  };
524
536
 
537
+ // Set displayName for the inner component
538
+ RecyclerViewComponent.displayName = "FlashList";
539
+
525
540
  // Type definition for the RecyclerView component
526
541
  type RecyclerViewType = <T>(
527
- props: RecyclerViewProps<T> & { ref?: React.Ref<any> }
542
+ props: RecyclerViewProps<T> & { ref?: React.Ref<FlashListRef<T>> }
528
543
  ) => React.JSX.Element;
529
544
 
530
545
  // Create and export the memoized, forwarded ref component
@@ -1,20 +1,26 @@
1
1
  import { createContext, useContext } from "react";
2
2
 
3
+ import { FlashListRef } from "../FlashListRef";
4
+
3
5
  import { CompatScroller } from "./components/CompatScroller";
4
6
 
5
- export interface RecyclerViewContext {
7
+ export interface RecyclerViewContext<T> {
6
8
  layout: () => void;
7
- getRef: () => React.Ref<any>;
8
- getScrollViewRef: () => React.RefObject<CompatScroller | null>;
9
+ getRef: () => FlashListRef<T> | null;
10
+ getScrollViewRef: () => CompatScroller | null;
9
11
  markChildLayoutAsPending: (id: string) => void;
10
12
  unmarkChildLayoutAsPending: (id: string) => void;
11
13
  }
12
14
 
13
15
  const RecyclerViewContextInstance = createContext<
14
- RecyclerViewContext | undefined
16
+ RecyclerViewContext<unknown> | undefined
15
17
  >(undefined);
16
18
 
17
19
  export const RecyclerViewContextProvider = RecyclerViewContextInstance.Provider;
18
- export function useRecyclerViewContext() {
19
- return useContext(RecyclerViewContextInstance);
20
+ export function useRecyclerViewContext<T>():
21
+ | RecyclerViewContext<T>
22
+ | undefined {
23
+ return useContext(RecyclerViewContextInstance) as
24
+ | RecyclerViewContext<T>
25
+ | undefined;
20
26
  }
@@ -9,30 +9,26 @@ import {
9
9
  } from "./layout-managers/LayoutManager";
10
10
  import { RVLinearLayoutManagerImpl } from "./layout-managers/LinearLayoutManager";
11
11
  import { RVMasonryLayoutManagerImpl } from "./layout-managers/MasonryLayoutManager";
12
- import { RecycleKeyManagerImpl, RecycleKeyManager } from "./RecycleKeyManager";
13
12
  import { RecyclerViewProps } from "./RecyclerViewProps";
14
13
  import {
15
14
  RVEngagedIndicesTracker,
16
15
  RVEngagedIndicesTrackerImpl,
17
16
  Velocity,
18
17
  } from "./helpers/EngagedIndicesTracker";
19
-
20
- // Abstracts layout manager, key manager and viewability manager and generates render stack (progressively on load)
18
+ import { RenderStackManager } from "./RenderStackManager";
19
+ // Abstracts layout manager, render stack manager and viewability manager and generates render stack (progressively on load)
21
20
  export class RecyclerViewManager<T> {
22
21
  private initialDrawBatchSize = 1;
23
22
  private engagedIndicesTracker: RVEngagedIndicesTracker;
24
- private recycleKeyManager: RecycleKeyManager;
23
+ private renderStackManager: RenderStackManager;
25
24
  private layoutManager?: RVLayoutManager;
26
25
  // Map of index to key
27
- private renderStack: Map<number, string> = new Map();
28
26
  private isFirstLayoutComplete = false;
29
27
  private hasRenderedProgressively = false;
30
- private props: RecyclerViewProps<T>;
28
+ private propsRef: RecyclerViewProps<T>;
31
29
  private itemViewabilityManager: ViewabilityManager<T>;
32
- private allocatedKeyTracker: Set<string> = new Set();
33
30
  private _isDisposed = false;
34
31
 
35
- public disableRecycling = false;
36
32
  public firstItemOffset = 0;
37
33
  public ignoreScrollEvents = false;
38
34
 
@@ -45,74 +41,46 @@ export class RecyclerViewManager<T> {
45
41
  }
46
42
 
47
43
  constructor(props: RecyclerViewProps<T>) {
48
- this.props = props;
44
+ this.getStableId = this.getStableId.bind(this);
45
+ this.getItemType = this.getItemType.bind(this);
46
+ this.propsRef = props;
49
47
  this.engagedIndicesTracker = new RVEngagedIndicesTrackerImpl();
50
- this.recycleKeyManager = new RecycleKeyManagerImpl();
48
+ this.renderStackManager = new RenderStackManager(
49
+ props.maxItemsInRecyclePool
50
+ );
51
51
  this.itemViewabilityManager = new ViewabilityManager<T>(this as any);
52
52
  }
53
53
 
54
54
  // updates render stack based on the engaged indices which are sorted. Recycles unused keys.
55
- // TODO: Write comprehensive tests for this function
56
55
  private updateRenderStack = (engagedIndices: ConsecutiveNumbers): void => {
57
- // console.log("updateRenderStack", engagedIndices);
58
-
59
- this.allocatedKeyTracker.clear();
60
- const newRenderStack = new Map<number, string>();
61
- for (const [index, key] of this.renderStack) {
62
- if (!engagedIndices.includes(index)) {
63
- this.recycleKeyManager.recycleKey(key);
64
- }
65
- }
66
- if (this.disableRecycling) {
67
- this.recycleKeyManager.clearPool();
68
- }
69
- for (const index of engagedIndices) {
70
- const currentKey = this.renderStack.get(index);
71
-
72
- if (
73
- currentKey &&
74
- !this.disableRecycling &&
75
- !this.allocatedKeyTracker.has(currentKey)
76
- ) {
77
- this.recycleKeyManager.recycleKey(currentKey);
78
- }
79
-
80
- const newKey = this.recycleKeyManager.getKey(
81
- this.getItemType(index),
82
- this.getStableId(index),
83
- currentKey
84
- );
85
- this.allocatedKeyTracker.add(newKey);
86
- newRenderStack.set(index, newKey);
87
- }
88
- // DANGER
89
- for (const [index, key] of this.renderStack) {
90
- if (
91
- this.recycleKeyManager.hasKeyInPool(key) &&
92
- !newRenderStack.has(index) &&
93
- index < (this.props.data?.length ?? 0)
94
- ) {
95
- this.allocatedKeyTracker.add(key);
96
- newRenderStack.set(index, key);
97
- }
98
- }
99
-
100
- this.renderStack = newRenderStack;
56
+ this.renderStackManager.sync(
57
+ this.getStableId,
58
+ this.getItemType,
59
+ engagedIndices,
60
+ this.getDataLength()
61
+ );
101
62
  };
102
63
 
64
+ get props() {
65
+ return this.propsRef;
66
+ }
67
+
103
68
  setOffsetProjectionEnabled(value: boolean) {
104
69
  this.engagedIndicesTracker.enableOffsetProjection = value;
105
70
  }
106
71
 
107
72
  updateProps(props: RecyclerViewProps<T>) {
108
- this.props = props;
73
+ this.propsRef = props;
109
74
  this.engagedIndicesTracker.drawDistance =
110
75
  props.drawDistance ?? this.engagedIndicesTracker.drawDistance;
111
- if (this.props.drawDistance === 0) {
76
+ if (this.propsRef.drawDistance === 0) {
112
77
  this.initialDrawBatchSize = 1;
113
78
  } else {
114
79
  this.initialDrawBatchSize = (props.numColumns ?? 1) * 2;
115
80
  }
81
+ this.initialDrawBatchSize =
82
+ this.propsRef.overrideProps?.initialDrawBatchSize ??
83
+ this.initialDrawBatchSize;
116
84
  }
117
85
 
118
86
  /**
@@ -124,7 +92,7 @@ export class RecyclerViewManager<T> {
124
92
  offset: number,
125
93
  velocity?: Velocity
126
94
  ): ConsecutiveNumbers | undefined {
127
- if (this.layoutManager && !this.isDisposed) {
95
+ if (this.layoutManager && !this._isDisposed) {
128
96
  const engagedIndices = this.engagedIndicesTracker.updateScrollOffset(
129
97
  offset - this.firstItemOffset,
130
98
  velocity,
@@ -147,6 +115,10 @@ export class RecyclerViewManager<T> {
147
115
  return this.isFirstLayoutComplete;
148
116
  }
149
117
 
118
+ disableRecycling(disable: boolean) {
119
+ this.renderStackManager.disableRecycling = disable;
120
+ }
121
+
150
122
  getLayout(index: number) {
151
123
  if (!this.layoutManager) {
152
124
  throw new Error(
@@ -156,6 +128,17 @@ export class RecyclerViewManager<T> {
156
128
  return this.layoutManager.getLayout(index);
157
129
  }
158
130
 
131
+ tryGetLayout(index: number) {
132
+ if (
133
+ this.layoutManager &&
134
+ index >= 0 &&
135
+ index < this.layoutManager.getLayoutCount()
136
+ ) {
137
+ return this.layoutManager.getLayout(index);
138
+ }
139
+ return undefined;
140
+ }
141
+
159
142
  // Doesn't include header / foot etc
160
143
  getChildContainerDimensions() {
161
144
  if (!this.layoutManager) {
@@ -167,7 +150,7 @@ export class RecyclerViewManager<T> {
167
150
  }
168
151
 
169
152
  getRenderStack() {
170
- return this.renderStack;
153
+ return this.renderStackManager.getRenderStack();
171
154
  }
172
155
 
173
156
  getWindowSize() {
@@ -187,10 +170,10 @@ export class RecyclerViewManager<T> {
187
170
  getMaxScrollOffset() {
188
171
  return Math.max(
189
172
  0,
190
- (this.props.horizontal
173
+ (this.propsRef.horizontal
191
174
  ? this.getChildContainerDimensions().width
192
175
  : this.getChildContainerDimensions().height) -
193
- (this.props.horizontal
176
+ (this.propsRef.horizontal
194
177
  ? this.getWindowSize().width
195
178
  : this.getWindowSize().height) +
196
179
  this.firstItemOffset
@@ -216,7 +199,7 @@ export class RecyclerViewManager<T> {
216
199
  if (
217
200
  this.layoutManager &&
218
201
  Boolean(this.layoutManager?.isHorizontal()) !==
219
- Boolean(this.props.horizontal)
202
+ Boolean(this.propsRef.horizontal)
220
203
  ) {
221
204
  throw new Error(
222
205
  "Horizontal prop cannot be toggled, you can use a key on FlashList to recreate it."
@@ -228,16 +211,17 @@ export class RecyclerViewManager<T> {
228
211
  this.layoutManager = new LayoutManagerClass(
229
212
  {
230
213
  windowSize,
231
- maxColumns: this.props.numColumns ?? 1,
232
- horizontal: Boolean(this.props.horizontal),
233
- optimizeItemArrangement: this.props.optimizeItemArrangement ?? true,
214
+ maxColumns: this.propsRef.numColumns ?? 1,
215
+ horizontal: Boolean(this.propsRef.horizontal),
216
+ optimizeItemArrangement:
217
+ this.propsRef.optimizeItemArrangement ?? true,
234
218
  overrideItemLayout: (index, layout) => {
235
- this.props?.overrideItemLayout?.(
219
+ this.propsRef?.overrideItemLayout?.(
236
220
  layout,
237
- this.props.data![index],
221
+ this.propsRef.data![index],
238
222
  index,
239
- this.props.numColumns ?? 1,
240
- this.props.extraData
223
+ this.propsRef.numColumns ?? 1,
224
+ this.propsRef.extraData
241
225
  );
242
226
  },
243
227
  },
@@ -246,9 +230,9 @@ export class RecyclerViewManager<T> {
246
230
  } else {
247
231
  this.layoutManager.updateLayoutParams({
248
232
  windowSize,
249
- maxColumns: this.props.numColumns ?? 1,
250
- horizontal: Boolean(this.props.horizontal),
251
- optimizeItemArrangement: this.props.optimizeItemArrangement ?? true,
233
+ maxColumns: this.propsRef.numColumns ?? 1,
234
+ horizontal: Boolean(this.propsRef.horizontal),
235
+ optimizeItemArrangement: this.propsRef.optimizeItemArrangement ?? true,
252
236
  });
253
237
  }
254
238
  }
@@ -257,7 +241,7 @@ export class RecyclerViewManager<T> {
257
241
  return this.layoutManager !== undefined;
258
242
  }
259
243
 
260
- getVisibleIndices() {
244
+ computeVisibleIndices() {
261
245
  if (!this.layoutManager) {
262
246
  throw new Error(
263
247
  "LayoutManager is not initialized, visible indices are not unavailable"
@@ -295,9 +279,9 @@ export class RecyclerViewManager<T> {
295
279
  // Using higher buffer for masonry to avoid missing items
296
280
  this.itemViewabilityManager.shouldListenToVisibleIndices &&
297
281
  this.itemViewabilityManager.updateViewableItems(
298
- this.props.masonry
282
+ this.propsRef.masonry
299
283
  ? this.engagedIndicesTracker.getEngagedIndices().toArray()
300
- : this.getVisibleIndices().toArray()
284
+ : this.computeVisibleIndices().toArray()
301
285
  );
302
286
  }
303
287
 
@@ -311,7 +295,7 @@ export class RecyclerViewManager<T> {
311
295
 
312
296
  processDataUpdate() {
313
297
  if (this.hasLayout()) {
314
- this.modifyChildrenLayout([], this.props.data?.length ?? 0);
298
+ this.modifyChildrenLayout([], this.propsRef.data?.length ?? 0);
315
299
  if (!this.recomputeEngagedIndices()) {
316
300
  // recomputeEngagedIndices will update the render stack if there are any changes in the engaged indices.
317
301
  // It's important to update render stack so that elements are assgined right keys incase items were deleted.
@@ -331,28 +315,28 @@ export class RecyclerViewManager<T> {
331
315
 
332
316
  getInitialScrollIndex() {
333
317
  return (
334
- this.props.initialScrollIndex ??
335
- (this.props.maintainVisibleContentPosition?.startRenderingFromBottom
318
+ this.propsRef.initialScrollIndex ??
319
+ (this.propsRef.maintainVisibleContentPosition?.startRenderingFromBottom
336
320
  ? this.getDataLength() - 1
337
321
  : undefined)
338
322
  );
339
323
  }
340
324
 
341
325
  getDataLength() {
342
- return this.props.data?.length ?? 0;
326
+ return this.propsRef.data?.length ?? 0;
343
327
  }
344
328
 
345
329
  private getLayoutManagerClass() {
346
330
  // throw errors for incompatible props
347
- if (this.props.masonry && this.props.horizontal) {
331
+ if (this.propsRef.masonry && this.propsRef.horizontal) {
348
332
  throw new Error("Masonry and horizontal props are incompatible");
349
333
  }
350
- if ((this.props.numColumns ?? 1) > 1 && this.props.horizontal) {
334
+ if ((this.propsRef.numColumns ?? 1) > 1 && this.propsRef.horizontal) {
351
335
  throw new Error("numColumns and horizontal props are incompatible");
352
336
  }
353
- return this.props.masonry
337
+ return this.propsRef.masonry
354
338
  ? RVMasonryLayoutManagerImpl
355
- : (this.props.numColumns ?? 1) > 1 && !this.props.horizontal
339
+ : (this.propsRef.numColumns ?? 1) > 1 && !this.propsRef.horizontal
356
340
  ? RVGridLayoutManagerImpl
357
341
  : RVLinearLayoutManagerImpl;
358
342
  }
@@ -366,7 +350,7 @@ export class RecyclerViewManager<T> {
366
350
  const initialItemLayout = this.layoutManager?.getLayout(
367
351
  initialScrollIndex ?? 0
368
352
  );
369
- const initialItemOffset = this.props.horizontal
353
+ const initialItemOffset = this.propsRef.horizontal
370
354
  ? initialItemLayout?.x
371
355
  : initialItemLayout?.y;
372
356
 
@@ -391,7 +375,7 @@ export class RecyclerViewManager<T> {
391
375
  const layoutManager = this.layoutManager;
392
376
  if (layoutManager) {
393
377
  this.applyInitialScrollAdjustment();
394
- const visibleIndices = this.getVisibleIndices();
378
+ const visibleIndices = this.computeVisibleIndices();
395
379
  // console.log("---------> visibleIndices", visibleIndices);
396
380
  this.hasRenderedProgressively = visibleIndices.every(
397
381
  (index) =>
@@ -412,7 +396,7 @@ export class RecyclerViewManager<T> {
412
396
  0,
413
397
  Math.min(
414
398
  visibleIndices.length,
415
- this.renderStack.size + this.initialDrawBatchSize
399
+ this.getRenderStack().size + this.initialDrawBatchSize
416
400
  )
417
401
  )
418
402
  );
@@ -421,13 +405,14 @@ export class RecyclerViewManager<T> {
421
405
 
422
406
  private getItemType(index: number): string {
423
407
  return (
424
- this.props.getItemType?.(this.props.data![index], index) ?? "default"
408
+ this.propsRef.getItemType?.(this.propsRef.data![index], index) ??
409
+ "default"
425
410
  ).toString();
426
411
  }
427
412
 
428
413
  private getStableId(index: number): string {
429
414
  return (
430
- this.props.keyExtractor?.(this.props.data![index], index) ??
415
+ this.propsRef.keyExtractor?.(this.propsRef.data![index], index) ??
431
416
  index.toString()
432
417
  );
433
418
  }