Skip to content

Commit 600f11f

Browse files
authored
docs: document useBenchmark (#1913)
1 parent 8d923d0 commit 600f11f

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# List Profiling with useBenchmark
2+
3+
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.
4+
5+
## Basic Usage
6+
7+
```tsx
8+
import { useRef } from "react";
9+
import { FlashList, FlashListRef, useBenchmark } from "@shopify/flash-list";
10+
11+
function MyList() {
12+
const flashListRef = useRef<FlashListRef<MyDataType>>(null);
13+
14+
// Basic benchmark setup
15+
useBenchmark(flashListRef, (result) => {
16+
console.log("Benchmark complete:", result.formattedString);
17+
});
18+
19+
return <FlashList ref={flashListRef} data={data} renderItem={renderItem} />;
20+
}
21+
```
22+
23+
## Manual Benchmark Control
24+
25+
For more control over when the benchmark runs, use the `startManually` option:
26+
27+
```tsx
28+
const { startBenchmark, isBenchmarkRunning } = useBenchmark(
29+
flashListRef,
30+
(result) => {
31+
if (!result.interrupted) {
32+
Alert.alert("Benchmark Complete", result.formattedString);
33+
}
34+
},
35+
{
36+
startManually: true,
37+
repeatCount: 3,
38+
speedMultiplier: 1.5,
39+
}
40+
);
41+
42+
// Trigger benchmark on button press
43+
<Button
44+
title={isBenchmarkRunning ? "Running..." : "Start Benchmark"}
45+
onPress={startBenchmark}
46+
disabled={isBenchmarkRunning}
47+
/>;
48+
```
49+
50+
## Configuration Options
51+
52+
The `useBenchmark` hook accepts an optional `BenchmarkParams` object:
53+
54+
| Parameter | Type | Default | Description |
55+
| ----------------- | ------- | ------- | ----------------------------------------------------------------------- |
56+
| `startDelayInMs` | number | 3000 | Delay before automatic benchmark start (in milliseconds) |
57+
| `speedMultiplier` | number | 1 | Multiplier for scroll speed (higher = faster scrolling) |
58+
| `repeatCount` | number | 1 | Number of times to repeat the benchmark |
59+
| `startManually` | boolean | false | Prevent automatic start, use returned `startBenchmark` function instead |
60+
61+
## Understanding Results
62+
63+
The benchmark returns a `BenchmarkResult` object containing:
64+
65+
```typescript
66+
interface BenchmarkResult {
67+
js?: {
68+
averageFPS: number;
69+
minFPS: number;
70+
maxFPS: number;
71+
};
72+
interrupted: boolean;
73+
suggestions: string[];
74+
formattedString?: string;
75+
}
76+
```
77+
78+
### Key Metrics
79+
80+
- **Average FPS**: The average JavaScript frames per second during scrolling
81+
- **Min FPS**: The lowest FPS recorded
82+
- **Max FPS**: The highest FPS recorded
83+
84+
### Interpreting Results
85+
86+
- **Good Performance**: Average FPS above 50
87+
- **Acceptable Performance**: Average FPS between 35-50
88+
- **Poor Performance**: Average FPS below 35
89+
90+
## Performance Suggestions
91+
92+
The benchmark automatically provides suggestions based on your results:
93+
94+
1. **Low JS FPS** (< 35 FPS): Indicates components are doing too much work. Consider:
95+
96+
- Optimizing render methods
97+
- Reducing component complexity
98+
- Implementing memoization
99+
- Minimizing re-renders
100+
101+
2. **Small Dataset** (< 200 items): Testing with larger datasets provides more realistic performance metrics
102+
103+
## Example
104+
105+
```tsx
106+
const generateData = (count: number): DataItem[] => {
107+
return Array.from({ length: count }, (_, index) => ({
108+
id: `item-${index}`,
109+
title: `Item ${index}`,
110+
value: Math.floor(Math.random() * 100),
111+
}));
112+
};
113+
114+
const ManualBenchmarkExample = () => {
115+
const flashListRef = useRef<FlashListRef<DataItem>>(null);
116+
const [data] = useState(() => generateData(500));
117+
const [benchmarkResult, setBenchmarkResult] = useState<string>("");
118+
119+
const { startBenchmark, isBenchmarkRunning } = useBenchmark(
120+
flashListRef,
121+
(result) => {
122+
if (!result.interrupted) {
123+
setBenchmarkResult(result.formattedString || "No results");
124+
Alert.alert("Benchmark Complete", result.formattedString);
125+
}
126+
},
127+
{
128+
startManually: true,
129+
repeatCount: 3,
130+
speedMultiplier: 1.5,
131+
}
132+
);
133+
134+
const renderItem = ({ item }: { item: DataItem }) => (
135+
<View style={styles.item}>
136+
<Text style={styles.title}>{item.title}</Text>
137+
<Text style={styles.value}>Value: {item.value}</Text>
138+
</View>
139+
);
140+
141+
return (
142+
<View style={styles.container}>
143+
<View style={styles.header}>
144+
<Text style={styles.headerText}>Manual Benchmark Example</Text>
145+
<Button
146+
title={isBenchmarkRunning ? "Running..." : "Start Benchmark"}
147+
onPress={startBenchmark}
148+
disabled={isBenchmarkRunning}
149+
/>
150+
</View>
151+
152+
<FlashList
153+
ref={flashListRef}
154+
data={data}
155+
renderItem={renderItem}
156+
keyExtractor={(item) => item.id}
157+
/>
158+
159+
{benchmarkResult ? (
160+
<View style={styles.resultContainer}>
161+
<Text style={styles.resultText}>{benchmarkResult}</Text>
162+
</View>
163+
) : null}
164+
</View>
165+
);
166+
};
167+
```
168+
169+
## Best Practices
170+
171+
1. **Test with Production Data**: Use realistic data sizes and complexity
172+
2. **Run Multiple Iterations**: Use `repeatCount` for more accurate averages
173+
3. **Test on Target Devices**: Performance varies significantly across devices
174+
4. **Benchmark Before and After**: Compare results when making optimizations
175+
5. **Consider User Scenarios**: Test with different scroll speeds using `speedMultiplier`

0 commit comments

Comments
 (0)