@shopify/flash-list 2.0.0-alpha.9 → 2.0.0-rc.1

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 (180) hide show
  1. package/README.md +37 -97
  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 +15 -8
  10. package/dist/FlashListProps.d.ts.map +1 -1
  11. package/dist/FlashListProps.js.map +1 -1
  12. package/dist/FlashListRef.d.ts +305 -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/MasonryFlashList.js.map +1 -1
  17. package/dist/__tests__/RecyclerView.test.js +62 -27
  18. package/dist/__tests__/RecyclerView.test.js.map +1 -1
  19. package/dist/__tests__/RenderStackManager.test.d.ts +2 -0
  20. package/dist/__tests__/RenderStackManager.test.d.ts.map +1 -0
  21. package/dist/__tests__/RenderStackManager.test.js +486 -0
  22. package/dist/__tests__/RenderStackManager.test.js.map +1 -0
  23. package/dist/__tests__/helpers/createLayoutManager.d.ts.map +1 -1
  24. package/dist/__tests__/helpers/createLayoutManager.js +3 -4
  25. package/dist/__tests__/helpers/createLayoutManager.js.map +1 -1
  26. package/dist/__tests__/useUnmountAwareCallbacks.test.js +1 -1
  27. package/dist/__tests__/useUnmountAwareCallbacks.test.js.map +1 -1
  28. package/dist/benchmark/useFlatListBenchmark.js +8 -7
  29. package/dist/benchmark/useFlatListBenchmark.js.map +1 -1
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/native/config/PlatformHelper.android.d.ts +1 -0
  34. package/dist/native/config/PlatformHelper.android.d.ts.map +1 -1
  35. package/dist/native/config/PlatformHelper.android.js +1 -0
  36. package/dist/native/config/PlatformHelper.android.js.map +1 -1
  37. package/dist/native/config/PlatformHelper.d.ts +1 -0
  38. package/dist/native/config/PlatformHelper.d.ts.map +1 -1
  39. package/dist/native/config/PlatformHelper.ios.d.ts +1 -0
  40. package/dist/native/config/PlatformHelper.ios.d.ts.map +1 -1
  41. package/dist/native/config/PlatformHelper.ios.js +1 -0
  42. package/dist/native/config/PlatformHelper.ios.js.map +1 -1
  43. package/dist/native/config/PlatformHelper.js +1 -0
  44. package/dist/native/config/PlatformHelper.js.map +1 -1
  45. package/dist/native/config/PlatformHelper.web.d.ts +1 -0
  46. package/dist/native/config/PlatformHelper.web.d.ts.map +1 -1
  47. package/dist/native/config/PlatformHelper.web.js +1 -0
  48. package/dist/native/config/PlatformHelper.web.js.map +1 -1
  49. package/dist/recyclerview/RecyclerView.d.ts +2 -1
  50. package/dist/recyclerview/RecyclerView.d.ts.map +1 -1
  51. package/dist/recyclerview/RecyclerView.js +63 -45
  52. package/dist/recyclerview/RecyclerView.js.map +1 -1
  53. package/dist/recyclerview/RecyclerViewContextProvider.d.ts +6 -5
  54. package/dist/recyclerview/RecyclerViewContextProvider.d.ts.map +1 -1
  55. package/dist/recyclerview/RecyclerViewContextProvider.js.map +1 -1
  56. package/dist/recyclerview/RecyclerViewManager.d.ts +21 -7
  57. package/dist/recyclerview/RecyclerViewManager.d.ts.map +1 -1
  58. package/dist/recyclerview/RecyclerViewManager.js +105 -113
  59. package/dist/recyclerview/RecyclerViewManager.js.map +1 -1
  60. package/dist/recyclerview/RenderStackManager.d.ts +85 -0
  61. package/dist/recyclerview/RenderStackManager.d.ts.map +1 -0
  62. package/dist/recyclerview/RenderStackManager.js +324 -0
  63. package/dist/recyclerview/RenderStackManager.js.map +1 -0
  64. package/dist/recyclerview/ViewHolder.d.ts.map +1 -1
  65. package/dist/recyclerview/ViewHolder.js +5 -3
  66. package/dist/recyclerview/ViewHolder.js.map +1 -1
  67. package/dist/recyclerview/ViewHolderCollection.d.ts +3 -1
  68. package/dist/recyclerview/ViewHolderCollection.d.ts.map +1 -1
  69. package/dist/recyclerview/ViewHolderCollection.js +23 -8
  70. package/dist/recyclerview/ViewHolderCollection.js.map +1 -1
  71. package/dist/recyclerview/components/ScrollAnchor.d.ts +2 -2
  72. package/dist/recyclerview/components/ScrollAnchor.d.ts.map +1 -1
  73. package/dist/recyclerview/components/ScrollAnchor.js +9 -5
  74. package/dist/recyclerview/components/ScrollAnchor.js.map +1 -1
  75. package/dist/recyclerview/components/StickyHeaders.d.ts +1 -1
  76. package/dist/recyclerview/components/StickyHeaders.d.ts.map +1 -1
  77. package/dist/recyclerview/components/StickyHeaders.js +39 -32
  78. package/dist/recyclerview/components/StickyHeaders.js.map +1 -1
  79. package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts +45 -1
  80. package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts.map +1 -1
  81. package/dist/recyclerview/helpers/EngagedIndicesTracker.js +77 -20
  82. package/dist/recyclerview/helpers/EngagedIndicesTracker.js.map +1 -1
  83. package/dist/recyclerview/helpers/RenderTimeTracker.d.ts +10 -0
  84. package/dist/recyclerview/helpers/RenderTimeTracker.d.ts.map +1 -0
  85. package/dist/recyclerview/helpers/RenderTimeTracker.js +39 -0
  86. package/dist/recyclerview/helpers/RenderTimeTracker.js.map +1 -0
  87. package/dist/recyclerview/helpers/VelocityTracker.d.ts +29 -0
  88. package/dist/recyclerview/helpers/VelocityTracker.d.ts.map +1 -0
  89. package/dist/recyclerview/helpers/VelocityTracker.js +70 -0
  90. package/dist/recyclerview/helpers/VelocityTracker.js.map +1 -0
  91. package/dist/recyclerview/hooks/useBoundDetection.d.ts +1 -2
  92. package/dist/recyclerview/hooks/useBoundDetection.d.ts.map +1 -1
  93. package/dist/recyclerview/hooks/useBoundDetection.js +19 -16
  94. package/dist/recyclerview/hooks/useBoundDetection.js.map +1 -1
  95. package/dist/recyclerview/hooks/useMappingHelper.d.ts +1 -1
  96. package/dist/recyclerview/hooks/useMappingHelper.d.ts.map +1 -1
  97. package/dist/recyclerview/hooks/useMappingHelper.js +1 -1
  98. package/dist/recyclerview/hooks/useMappingHelper.js.map +1 -1
  99. package/dist/recyclerview/hooks/useOnLoad.d.ts.map +1 -1
  100. package/dist/recyclerview/hooks/useOnLoad.js +4 -6
  101. package/dist/recyclerview/hooks/useOnLoad.js.map +1 -1
  102. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts +3 -48
  103. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts.map +1 -1
  104. package/dist/recyclerview/hooks/useRecyclerViewController.js +174 -123
  105. package/dist/recyclerview/hooks/useRecyclerViewController.js.map +1 -1
  106. package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts +2 -0
  107. package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts.map +1 -1
  108. package/dist/recyclerview/hooks/useRecyclerViewManager.js +10 -1
  109. package/dist/recyclerview/hooks/useRecyclerViewManager.js.map +1 -1
  110. package/dist/recyclerview/hooks/useSecondaryProps.js +1 -1
  111. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts +10 -3
  112. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts.map +1 -1
  113. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js +33 -4
  114. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js.map +1 -1
  115. package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts +6 -0
  116. package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts.map +1 -1
  117. package/dist/recyclerview/layout-managers/GridLayoutManager.js +27 -5
  118. package/dist/recyclerview/layout-managers/GridLayoutManager.js.map +1 -1
  119. package/dist/recyclerview/layout-managers/LayoutManager.d.ts +10 -16
  120. package/dist/recyclerview/layout-managers/LayoutManager.d.ts.map +1 -1
  121. package/dist/recyclerview/layout-managers/LayoutManager.js +4 -14
  122. package/dist/recyclerview/layout-managers/LayoutManager.js.map +1 -1
  123. package/dist/tsconfig.tsbuildinfo +1 -1
  124. package/dist/viewability/ViewToken.d.ts +2 -2
  125. package/dist/viewability/ViewToken.d.ts.map +1 -1
  126. package/dist/viewability/ViewabilityHelper.js +1 -1
  127. package/dist/viewability/ViewabilityHelper.js.map +1 -1
  128. package/dist/viewability/ViewabilityManager.d.ts.map +1 -1
  129. package/dist/viewability/ViewabilityManager.js +1 -2
  130. package/dist/viewability/ViewabilityManager.js.map +1 -1
  131. package/jestSetup.js +30 -11
  132. package/package.json +2 -1
  133. package/src/AnimatedFlashList.ts +3 -2
  134. package/src/FlashList.tsx +24 -0
  135. package/src/FlashListProps.ts +20 -8
  136. package/src/FlashListRef.ts +320 -0
  137. package/src/MasonryFlashList.tsx +2 -2
  138. package/src/__tests__/RecyclerView.test.tsx +83 -29
  139. package/src/__tests__/RenderStackManager.test.ts +575 -0
  140. package/src/__tests__/helpers/createLayoutManager.ts +2 -3
  141. package/src/__tests__/useUnmountAwareCallbacks.test.tsx +12 -12
  142. package/src/benchmark/useFlatListBenchmark.ts +2 -2
  143. package/src/index.ts +1 -0
  144. package/src/native/config/PlatformHelper.android.ts +1 -0
  145. package/src/native/config/PlatformHelper.ios.ts +1 -0
  146. package/src/native/config/PlatformHelper.ts +1 -0
  147. package/src/native/config/PlatformHelper.web.ts +1 -0
  148. package/src/recyclerview/RecyclerView.tsx +82 -52
  149. package/src/recyclerview/RecyclerViewContextProvider.ts +12 -6
  150. package/src/recyclerview/RecyclerViewManager.ts +123 -98
  151. package/src/recyclerview/RenderStackManager.ts +291 -0
  152. package/src/recyclerview/ViewHolder.tsx +5 -3
  153. package/src/recyclerview/ViewHolderCollection.tsx +33 -12
  154. package/src/recyclerview/components/ScrollAnchor.tsx +21 -9
  155. package/src/recyclerview/components/StickyHeaders.tsx +62 -44
  156. package/src/recyclerview/helpers/EngagedIndicesTracker.ts +118 -23
  157. package/src/recyclerview/helpers/RenderTimeTracker.ts +38 -0
  158. package/src/recyclerview/helpers/VelocityTracker.ts +77 -0
  159. package/src/recyclerview/hooks/useBoundDetection.ts +25 -18
  160. package/src/recyclerview/hooks/useMappingHelper.ts +1 -1
  161. package/src/recyclerview/hooks/useOnLoad.ts +4 -6
  162. package/src/recyclerview/hooks/useRecyclerViewController.tsx +199 -176
  163. package/src/recyclerview/hooks/useRecyclerViewManager.ts +11 -1
  164. package/src/recyclerview/hooks/useSecondaryProps.tsx +1 -1
  165. package/src/recyclerview/hooks/useUnmountAwareCallbacks.ts +39 -3
  166. package/src/recyclerview/layout-managers/GridLayoutManager.ts +30 -7
  167. package/src/recyclerview/layout-managers/LayoutManager.ts +12 -21
  168. package/src/viewability/ViewToken.ts +2 -2
  169. package/src/viewability/ViewabilityHelper.ts +1 -1
  170. package/src/viewability/ViewabilityManager.ts +6 -3
  171. package/dist/__tests__/RecycleKeyManager.test.d.ts +0 -2
  172. package/dist/__tests__/RecycleKeyManager.test.d.ts.map +0 -1
  173. package/dist/__tests__/RecycleKeyManager.test.js +0 -210
  174. package/dist/__tests__/RecycleKeyManager.test.js.map +0 -1
  175. package/dist/recyclerview/RecycleKeyManager.d.ts +0 -82
  176. package/dist/recyclerview/RecycleKeyManager.d.ts.map +0 -1
  177. package/dist/recyclerview/RecycleKeyManager.js +0 -135
  178. package/dist/recyclerview/RecycleKeyManager.js.map +0 -1
  179. package/src/__tests__/RecycleKeyManager.test.ts +0 -254
  180. package/src/recyclerview/RecycleKeyManager.ts +0 -185
@@ -25,7 +25,7 @@ export function useFlatListBenchmark(
25
25
  ) {
26
26
  useEffect(() => {
27
27
  const cancellable = new Cancellable();
28
- if (flatListRef.current) {
28
+ if (flatListRef.current && flatListRef.current.props) {
29
29
  if (!(Number(flatListRef.current.props.data?.length) > 0)) {
30
30
  throw new Error("Data is empty, cannot run benchmark");
31
31
  }
@@ -71,7 +71,7 @@ async function runScrollBenchmark(
71
71
  scrollSpeedMultiplier: number
72
72
  ): Promise<void> {
73
73
  if (flatListRef.current) {
74
- const horizontal = flatListRef.current.props.horizontal;
74
+ const horizontal = Boolean(flatListRef.current.props?.horizontal);
75
75
 
76
76
  const fromX = 0;
77
77
  const fromY = 0;
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import { RecyclerView } from "./recyclerview/RecyclerView";
5
5
 
6
6
  // Keep this unmodified for TS type checking
7
7
  export { default as FlashList } from "./FlashList";
8
+ export { FlashListRef } from "./FlashListRef";
8
9
  export {
9
10
  FlashListProps,
10
11
  ContentStyle,
@@ -3,6 +3,7 @@ import { BaseItemAnimator } from "recyclerlistview";
3
3
  const PlatformConfig = {
4
4
  defaultDrawDistance: 250,
5
5
  supportsOffsetCorrection: true,
6
+ trackAverageRenderTimeForOffsetProjection: true,
6
7
  // Using rotate instead of scaleY on Android to avoid performance issues. Issue: https://github.com/Shopify/flash-list/issues/751
7
8
  invertedTransformStyle: { transform: [{ rotate: "180deg" }] },
8
9
  invertedTransformStyleHorizontal: { transform: [{ rotate: "180deg" }] },
@@ -3,6 +3,7 @@ import { BaseItemAnimator } from "recyclerlistview";
3
3
  const PlatformConfig = {
4
4
  defaultDrawDistance: 250,
5
5
  supportsOffsetCorrection: true,
6
+ trackAverageRenderTimeForOffsetProjection: false,
6
7
  invertedTransformStyle: { transform: [{ scaleY: -1 }] },
7
8
  invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
8
9
  };
@@ -4,6 +4,7 @@ import { DefaultJSItemAnimator } from "recyclerlistview/dist/reactnative/platfor
4
4
  const PlatformConfig = {
5
5
  defaultDrawDistance: 250,
6
6
  supportsOffsetCorrection: false,
7
+ trackAverageRenderTimeForOffsetProjection: false,
7
8
  invertedTransformStyle: { transform: [{ scaleY: -1 }] },
8
9
  invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
9
10
  };
@@ -6,6 +6,7 @@ import { DefaultJSItemAnimator } from "recyclerlistview/dist/reactnative/platfor
6
6
  const PlatformConfig = {
7
7
  defaultDrawDistance: 500,
8
8
  supportsOffsetCorrection: false,
9
+ trackAverageRenderTimeForOffsetProjection: false,
9
10
  invertedTransformStyle: { transform: [{ scaleY: -1 }] },
10
11
  invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
11
12
  };
@@ -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,
@@ -47,6 +49,7 @@ import { useSecondaryProps } from "./hooks/useSecondaryProps";
47
49
  import { StickyHeaders, StickyHeaderRef } from "./components/StickyHeaders";
48
50
  import { ScrollAnchor, ScrollAnchorRef } from "./components/ScrollAnchor";
49
51
  import { useRecyclerViewController } from "./hooks/useRecyclerViewController";
52
+ import { RenderTimeTracker } from "./helpers/RenderTimeTracker";
50
53
 
51
54
  /**
52
55
  * Main RecyclerView component that handles list rendering, scrolling, and item recycling.
@@ -54,7 +57,7 @@ import { useRecyclerViewController } from "./hooks/useRecyclerViewController";
54
57
  */
55
58
  const RecyclerViewComponent = <T,>(
56
59
  props: RecyclerViewProps<T>,
57
- ref: React.Ref<any>
60
+ ref: React.Ref<FlashListRef<T>>
58
61
  ) => {
59
62
  // Destructure props and initialize refs
60
63
  const {
@@ -75,8 +78,6 @@ const RecyclerViewComponent = <T,>(
75
78
  ListFooterComponentStyle,
76
79
  ItemSeparatorComponent,
77
80
  renderScrollComponent,
78
- onScroll,
79
- disableRecycling,
80
81
  style,
81
82
  stickyHeaderIndices,
82
83
  maintainVisibleContentPosition,
@@ -84,6 +85,10 @@ const RecyclerViewComponent = <T,>(
84
85
  ...rest
85
86
  } = props;
86
87
 
88
+ const [renderTimeTracker] = useState(() => new RenderTimeTracker());
89
+
90
+ renderTimeTracker.startTracking();
91
+
87
92
  // Core refs for managing scroll view, internal view, and child container
88
93
  const scrollViewRef = useRef<CompatScroller>(null);
89
94
  const internalViewRef = useRef<CompatView>(null);
@@ -109,14 +114,14 @@ const RecyclerViewComponent = <T,>(
109
114
  );
110
115
 
111
116
  // Initialize core RecyclerView manager and content offset management
112
- const { recyclerViewManager } = useRecyclerViewManager(props);
113
- const { applyContentOffset, applyInitialScrollIndex } =
117
+ const { recyclerViewManager, velocityTracker } =
118
+ useRecyclerViewManager(props);
119
+ const { applyContentOffset, applyInitialScrollIndex, handlerMethods } =
114
120
  useRecyclerViewController(
115
121
  recyclerViewManager,
116
122
  ref,
117
123
  scrollViewRef,
118
- scrollAnchorRef,
119
- props
124
+ scrollAnchorRef
120
125
  );
121
126
 
122
127
  // Initialize view holder collection ref
@@ -126,11 +131,7 @@ const RecyclerViewComponent = <T,>(
126
131
  useOnListLoad(recyclerViewManager, onLoad);
127
132
 
128
133
  // Hook to detect when scrolling reaches list bounds
129
- const { checkBounds } = useBoundDetection(
130
- recyclerViewManager,
131
- props,
132
- scrollViewRef
133
- );
134
+ const { checkBounds } = useBoundDetection(recyclerViewManager, scrollViewRef);
134
135
 
135
136
  const isHorizontalRTL = I18nManager.isRTL && horizontal;
136
137
 
@@ -176,6 +177,7 @@ const RecyclerViewComponent = <T,>(
176
177
  * Effect to handle layout updates for list items
177
178
  * This ensures proper positioning and recycling of items
178
179
  */
180
+ // eslint-disable-next-line react-hooks/exhaustive-deps
179
181
  useLayoutEffect(() => {
180
182
  if (pendingChildIds.size > 0) {
181
183
  return;
@@ -183,7 +185,7 @@ const RecyclerViewComponent = <T,>(
183
185
  const layoutInfo = Array.from(refHolder, ([index, viewHolderRef]) => {
184
186
  const layout = measureItemLayout(
185
187
  viewHolderRef.current!,
186
- recyclerViewManager.getLayout(index)
188
+ recyclerViewManager.tryGetLayout(index)
187
189
  );
188
190
 
189
191
  // comapre height with stored layout
@@ -221,23 +223,11 @@ const RecyclerViewComponent = <T,>(
221
223
  if (recyclerViewManager.ignoreScrollEvents) {
222
224
  return;
223
225
  }
224
- let velocity = event.nativeEvent.velocity;
225
226
 
226
227
  let scrollOffset = horizontal
227
228
  ? event.nativeEvent.contentOffset.x
228
229
  : event.nativeEvent.contentOffset.y;
229
230
 
230
- if (!velocity) {
231
- const velocityValue =
232
- recyclerViewManager.getAbsoluteLastScrollOffset() < scrollOffset
233
- ? 1
234
- : -1;
235
- velocity = {
236
- x: horizontal ? velocityValue : 0,
237
- y: horizontal ? 0 : velocityValue,
238
- };
239
- }
240
-
241
231
  // Handle RTL (Right-to-Left) layout adjustments
242
232
  if (isHorizontalRTL) {
243
233
  scrollOffset = adjustOffsetForRTL(
@@ -245,18 +235,30 @@ const RecyclerViewComponent = <T,>(
245
235
  event.nativeEvent.contentSize.width,
246
236
  event.nativeEvent.layoutMeasurement.width
247
237
  );
248
- if (velocity) {
249
- velocity = {
250
- x: -velocity.x,
251
- y: velocity.y,
252
- };
253
- }
254
- }
255
- // Update scroll position and trigger re-render if needed
256
- if (recyclerViewManager.updateScrollOffset(scrollOffset, velocity)) {
257
- setRenderId((prev) => prev + 1);
258
238
  }
259
239
 
240
+ velocityTracker.computeVelocity(
241
+ scrollOffset,
242
+ recyclerViewManager.getAbsoluteLastScrollOffset(),
243
+ Boolean(horizontal),
244
+ (velocity, isMomentumEnd) => {
245
+ if (recyclerViewManager.ignoreScrollEvents) {
246
+ return;
247
+ }
248
+
249
+ if (isMomentumEnd) {
250
+ if (!recyclerViewManager.isOffsetProjectionEnabled) {
251
+ return;
252
+ }
253
+ recyclerViewManager.resetVelocityCompute();
254
+ }
255
+ // Update scroll position and trigger re-render if needed
256
+ if (recyclerViewManager.updateScrollOffset(scrollOffset, velocity)) {
257
+ setRenderId((prev) => prev + 1);
258
+ }
259
+ }
260
+ );
261
+
260
262
  // Update sticky headers and check bounds
261
263
  stickyHeaderRef.current?.reportScrollEvent(event.nativeEvent);
262
264
  checkBounds();
@@ -266,22 +268,31 @@ const RecyclerViewComponent = <T,>(
266
268
  recyclerViewManager.computeItemViewability();
267
269
 
268
270
  // Call user-provided onScroll handler
269
- onScroll?.(event);
271
+ recyclerViewManager.props.onScroll?.(event);
270
272
  },
271
- [horizontal, isHorizontalRTL, recyclerViewManager]
273
+ [
274
+ checkBounds,
275
+ horizontal,
276
+ isHorizontalRTL,
277
+ recyclerViewManager,
278
+ velocityTracker,
279
+ ]
272
280
  );
273
281
 
274
282
  // Create context for child components
275
- const recyclerViewContext: RecyclerViewContext = useMemo(() => {
283
+ const recyclerViewContext: RecyclerViewContext<T> = useMemo(() => {
276
284
  return {
277
285
  layout: () => {
278
286
  setLayoutTreeId((prev) => prev + 1);
279
287
  },
280
288
  getRef: () => {
281
- return ref;
289
+ if (recyclerViewManager.isDisposed) {
290
+ return null;
291
+ }
292
+ return handlerMethods;
282
293
  },
283
294
  getScrollViewRef: () => {
284
- return scrollViewRef;
295
+ return scrollViewRef.current;
285
296
  },
286
297
  markChildLayoutAsPending: (id: string) => {
287
298
  pendingChildIds.add(id);
@@ -293,7 +304,7 @@ const RecyclerViewComponent = <T,>(
293
304
  }
294
305
  },
295
306
  };
296
- }, [setLayoutTreeId]);
307
+ }, [handlerMethods, pendingChildIds, recyclerViewManager, setLayoutTreeId]);
297
308
 
298
309
  const parentRecyclerViewContext = useRecyclerViewContext();
299
310
  const recyclerViewId = useId();
@@ -328,7 +339,7 @@ const RecyclerViewComponent = <T,>(
328
339
  recyclerViewContext.layout();
329
340
  }
330
341
  },
331
- [recyclerViewManager]
342
+ [recyclerViewContext, recyclerViewManager]
332
343
  );
333
344
 
334
345
  // Get secondary props and components
@@ -368,7 +379,14 @@ const RecyclerViewComponent = <T,>(
368
379
  );
369
380
  }
370
381
  return null;
371
- }, [data, stickyHeaderIndices, renderItem, extraData]);
382
+ }, [
383
+ data,
384
+ stickyHeaderIndices,
385
+ renderItem,
386
+ scrollY,
387
+ recyclerViewManager,
388
+ extraData,
389
+ ]);
372
390
 
373
391
  // Set up scroll event handling with animation support for sticky headers
374
392
  const animatedEvent = useMemo(() => {
@@ -379,21 +397,23 @@ const RecyclerViewComponent = <T,>(
379
397
  );
380
398
  }
381
399
  return onScrollHandler;
382
- }, [onScrollHandler, stickyHeaders]);
400
+ }, [onScrollHandler, scrollY, stickyHeaders]);
401
+
402
+ const shouldMaintainVisibleContentPosition =
403
+ recyclerViewManager.shouldMaintainVisibleContentPosition();
383
404
 
384
405
  const maintainVisibleContentPositionInternal = useMemo(() => {
385
- if (maintainVisibleContentPosition?.disabled || horizontal) {
386
- return undefined;
387
- } else {
406
+ if (shouldMaintainVisibleContentPosition) {
388
407
  return {
389
408
  ...maintainVisibleContentPosition,
390
409
  minIndexForVisible: 0,
391
410
  };
392
411
  }
393
- }, [maintainVisibleContentPosition]);
412
+ return undefined;
413
+ }, [maintainVisibleContentPosition, shouldMaintainVisibleContentPosition]);
394
414
 
395
415
  const shouldRenderFromBottom =
396
- maintainVisibleContentPositionInternal?.startRenderingFromBottom ?? false;
416
+ maintainVisibleContentPosition?.startRenderingFromBottom ?? false;
397
417
 
398
418
  // Calculate minimum height adjustment for bottom rendering
399
419
  const adjustmentMinHeight = recyclerViewManager.hasLayout()
@@ -466,7 +486,10 @@ const RecyclerViewComponent = <T,>(
466
486
  >
467
487
  {/* Scroll anchor for maintaining content position */}
468
488
  {maintainVisibleContentPositionInternal && (
469
- <ScrollAnchor scrollAnchorRef={scrollAnchorRef} />
489
+ <ScrollAnchor
490
+ horizontal={Boolean(horizontal)}
491
+ scrollAnchorRef={scrollAnchorRef}
492
+ />
470
493
  )}
471
494
  {isHorizontalRTL && viewToMeasureBoundedSize}
472
495
  {renderHeader}
@@ -490,10 +513,14 @@ const RecyclerViewComponent = <T,>(
490
513
  onCommitLayoutEffect?.();
491
514
  }}
492
515
  onCommitEffect={() => {
516
+ renderTimeTracker.markRenderComplete();
517
+ recyclerViewManager.updateAverageRenderTime(
518
+ renderTimeTracker.getAverageRenderTime()
519
+ );
493
520
  applyInitialScrollIndex();
494
521
  checkBounds();
495
522
  recyclerViewManager.computeItemViewability();
496
- recyclerViewManager.disableRecycling = Boolean(disableRecycling);
523
+ recyclerViewManager.disableRecycling(false);
497
524
  }}
498
525
  CellRendererComponent={CellRendererComponent}
499
526
  ItemSeparatorComponent={ItemSeparatorComponent}
@@ -512,9 +539,12 @@ const RecyclerViewComponent = <T,>(
512
539
  );
513
540
  };
514
541
 
542
+ // Set displayName for the inner component
543
+ RecyclerViewComponent.displayName = "FlashList";
544
+
515
545
  // Type definition for the RecyclerView component
516
546
  type RecyclerViewType = <T>(
517
- props: RecyclerViewProps<T> & { ref?: React.Ref<any> }
547
+ props: RecyclerViewProps<T> & { ref?: React.Ref<FlashListRef<T>> }
518
548
  ) => React.JSX.Element;
519
549
 
520
550
  // 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
  }