1- import React , { useEffect } from "react" ;
1+ import React , { useEffect , useState , useCallback , useRef } from "react" ;
22
33import FlashList from "../FlashList" ;
44
@@ -28,6 +28,12 @@ export interface BenchmarkParams {
2828 * Blank area is negative when list is able to draw faster than the scroll speed.
2929 */
3030 sumNegativeBlankAreaValues ?: boolean ;
31+
32+ /**
33+ * When set to true, the benchmark will not start automatically.
34+ * Use the returned startBenchmark function to trigger it manually.
35+ */
36+ startManually ?: boolean ;
3137}
3238
3339export interface BenchmarkResult {
@@ -54,15 +60,27 @@ export function useBenchmark(
5460 undefined ,
5561 { sumNegativeValues : params . sumNegativeBlankAreaValues , startDelayInMs : 0 }
5662 ) ;
57- useEffect ( ( ) => {
63+ const [ isBenchmarkRunning , setIsBenchmarkRunning ] = useState ( false ) ;
64+ const cancellableRef = useRef < Cancellable | null > ( null ) ;
65+
66+ const startBenchmark = useCallback ( ( ) => {
67+ if ( isBenchmarkRunning ) {
68+ return ;
69+ }
70+
5871 const cancellable = new Cancellable ( ) ;
72+ cancellableRef . current = cancellable ;
5973 const suggestions : string [ ] = [ ] ;
74+
6075 if ( flashListRef . current ) {
6176 if ( ! ( Number ( flashListRef . current . props . data ?. length ) > 0 ) ) {
6277 throw new Error ( "Data is empty, cannot run benchmark" ) ;
6378 }
6479 }
65- const cancelTimeout = setTimeout ( async ( ) => {
80+
81+ setIsBenchmarkRunning ( true ) ;
82+
83+ const runBenchmark = async ( ) => {
6684 const jsFPSMonitor = new JSFPSMonitor ( ) ;
6785 jsFPSMonitor . startTracking ( ) ;
6886 for ( let i = 0 ; i < ( params . repeatCount || 1 ) ; i ++ ) {
@@ -89,14 +107,38 @@ export function useBenchmark(
89107 result . formattedString = getFormattedString ( result ) ;
90108 }
91109 callback ( result ) ;
110+ setIsBenchmarkRunning ( false ) ;
111+ } ;
112+
113+ runBenchmark ( ) ;
114+ } , [
115+ blankAreaResult ,
116+ callback ,
117+ flashListRef ,
118+ isBenchmarkRunning ,
119+ params . repeatCount ,
120+ params . speedMultiplier ,
121+ ] ) ;
122+
123+ useEffect ( ( ) => {
124+ if ( params . startManually ) {
125+ return ;
126+ }
127+
128+ const cancelTimeout = setTimeout ( ( ) => {
129+ startBenchmark ( ) ;
92130 } , params . startDelayInMs || 3000 ) ;
131+
93132 return ( ) => {
94133 clearTimeout ( cancelTimeout ) ;
95- cancellable . cancel ( ) ;
134+ if ( cancellableRef . current ) {
135+ cancellableRef . current . cancel ( ) ;
136+ }
96137 } ;
97138 // eslint-disable-next-line react-hooks/exhaustive-deps
98139 } , [ ] ) ;
99- return [ blankAreaTracker ] ;
140+
141+ return [ blankAreaTracker , { startBenchmark, isBenchmarkRunning } ] as const ;
100142}
101143
102144export function getFormattedString ( res : BenchmarkResult ) {
@@ -151,15 +193,14 @@ async function runScrollBenchmark(
151193) : Promise < void > {
152194 if ( flashListRef . current ) {
153195 const horizontal = flashListRef . current . props . horizontal ;
154- const rlv = flashListRef . current . recyclerlistview_unsafe ;
155- if ( rlv ) {
156- const rlvSize = rlv . getRenderedSize ( ) ;
157- const rlvContentSize = rlv . getContentDimension ( ) ;
196+ const windowSize = flashListRef . current . getWindowSize ( ) ;
197+ const contentSize = flashListRef . current . getChildContainerDimensions ( ) ;
158198
199+ if ( windowSize && contentSize ) {
159200 const fromX = 0 ;
160201 const fromY = 0 ;
161- const toX = rlvContentSize . width - rlvSize . width ;
162- const toY = rlvContentSize . height - rlvSize . height ;
202+ const toX = contentSize . width - windowSize . width ;
203+ const toY = contentSize . height - windowSize . height ;
163204
164205 const scrollNow = ( x : number , y : number ) => {
165206 flashListRef . current ?. scrollToOffset ( {
0 commit comments