List Profiling with useBenchmark
The useBenchmark hook provides a comprehensive way to measure and analyze the performance of your FlashList implementation. It automatically scrolls through your list while collecting performance metrics and provides actionable suggestions for optimization.
Basic Usageβ
import { useRef } from "react";
import { FlashList, FlashListRef, useBenchmark } from "@shopify/flash-list";
function MyList() {
const flashListRef = useRef<FlashListRef<MyDataType>>(null);
// Basic benchmark setup
useBenchmark(flashListRef, (result) => {
console.log("Benchmark complete:", result.formattedString);
});
return <FlashList ref={flashListRef} data={data} renderItem={renderItem} />;
}
Manual Benchmark Controlβ
For more control over when the benchmark runs, use the startManually option:
const { startBenchmark, isBenchmarkRunning } = useBenchmark(
flashListRef,
(result) => {
if (!result.interrupted) {
Alert.alert("Benchmark Complete", result.formattedString);
}
},
{
startManually: true,
repeatCount: 3,
speedMultiplier: 1.5,
}
);
// Trigger benchmark on button press
<Button
title={isBenchmarkRunning ? "Running..." : "Start Benchmark"}
onPress={startBenchmark}
disabled={isBenchmarkRunning}
/>;
Configuration Optionsβ
The useBenchmark hook accepts an optional BenchmarkParams object:
| Parameter | Type | Default | Description |
|---|---|---|---|
startDelayInMs | number | 3000 | Delay before automatic benchmark start (in milliseconds) |
speedMultiplier | number | 1 | Multiplier for scroll speed (higher = faster scrolling) |
repeatCount | number | 1 | Number of times to repeat the benchmark |
startManually | boolean | false | Prevent automatic start, use returned startBenchmark function instead |
Understanding Resultsβ
The benchmark returns a BenchmarkResult object containing:
interface BenchmarkResult {
js?: {
averageFPS: number;
minFPS: number;
maxFPS: number;
};
interrupted: boolean;
suggestions: string[];
formattedString?: string;
}
Key Metricsβ
- Average FPS: The average JavaScript frames per second during scrolling
- Min FPS: The lowest FPS recorded
- Max FPS: The highest FPS recorded
Interpreting Resultsβ
- Good Performance: Average FPS above 50
- Acceptable Performance: Average FPS between 35-50
- Poor Performance: Average FPS below 35
Performance Suggestionsβ
The benchmark automatically provides suggestions based on your results:
-
Low JS FPS (< 35 FPS): Indicates components are doing too much work. Consider:
- Optimizing render methods
- Reducing component complexity
- Implementing memoization
- Minimizing re-renders
-
Small Dataset (< 200 items): Testing with larger datasets provides more realistic performance metrics
Exampleβ
const generateData = (count: number): DataItem[] => {
return Array.from({ length: count }, (_, index) => ({
id: `item-${index}`,
title: `Item ${index}`,
value: Math.floor(Math.random() * 100),
}));
};
const ManualBenchmarkExample = () => {
const flashListRef = useRef<FlashListRef<DataItem>>(null);
const [data] = useState(() => generateData(500));
const [benchmarkResult, setBenchmarkResult] = useState<string>("");
const { startBenchmark, isBenchmarkRunning } = useBenchmark(
flashListRef,
(result) => {
if (!result.interrupted) {
setBenchmarkResult(result.formattedString || "No results");
Alert.alert("Benchmark Complete", result.formattedString);
}
},
{
startManually: true,
repeatCount: 3,
speedMultiplier: 1.5,
}
);
const renderItem = ({ item }: { item: DataItem }) => (
<View style={styles.item}>
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.value}>Value: {item.value}</Text>
</View>
);
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Manual Benchmark Example</Text>
<Button
title={isBenchmarkRunning ? "Running..." : "Start Benchmark"}
onPress={startBenchmark}
disabled={isBenchmarkRunning}
/>
</View>
<FlashList
ref={flashListRef}
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
{benchmarkResult ? (
<View style={styles.resultContainer}>
<Text style={styles.resultText}>{benchmarkResult}</Text>
</View>
) : null}
</View>
);
};
Best Practicesβ
- Test with Production Data: Use realistic data sizes and complexity
- Run Multiple Iterations: Use
repeatCountfor more accurate averages - Test on Target Devices: Performance varies significantly across devices
- Benchmark Before and After: Compare results when making optimizations
- Consider User Scenarios: Test with different scroll speeds using
speedMultiplier