Hai cách dùng Profiler:
- <Profiler> component: programmatic, log metrics trong production.
- React DevTools Profiler tab: UI flame chart, dùng khi develop.
3 metrics quan trọng:
| Metric | Ý nghĩa |
|---|---|
actualDuration | Thời gian render thực tế (đã trừ memoization skip) |
baseDuration | Thời gian render nếu không có memoization |
commitTime | Timestamp lúc commit DOM |
actualDuration << baseDuration → memoization (React.memo/useMemo) đang hoạt động tốt. actualDuration ≈ baseDuration → memoization không skip gì, có thể là vô ích hoặc shallow compare fail.
<Profiler id="OrderList" onRender={(id, phase, actualDuration, baseDuration) => {
// 16ms = 60fps budget — vượt là user thấy lag
if (actualDuration > 16) {
console.warn(`[${id}] ${phase} took ${actualDuration.toFixed(2)}ms`)
}
}}>
<OrderList orders={orders} />
</Profiler>Quy tắc tối ưu: Profile trước, optimize sau. DevTools Profiler flame chart màu cam/đỏ = component cần xem trước, đừng đoán bottleneck.
Two ways to use Profiler:
- <Profiler> component: programmatic, log metrics in production.
- React DevTools Profiler tab: UI flame chart for development.
3 key metrics:
| Metric | Meaning |
|---|---|
actualDuration | Real render time (after memoization skipped subtrees) |
baseDuration | Render time without any memoization |
commitTime | Timestamp when changes commit to the DOM |
actualDuration << baseDuration → memoization (React.memo/useMemo) is working well. actualDuration ≈ baseDuration → memoization is not skipping anything, possibly useless or shallow-compare failing.
<Profiler id="OrderList" onRender={(id, phase, actualDuration, baseDuration) => {
// 16ms = 60fps budget — exceeding it means visible lag
if (actualDuration > 16) {
console.warn(`[${id}] ${phase} took ${actualDuration.toFixed(2)}ms`)
}
}}>
<OrderList orders={orders} />
</Profiler>Optimization rule: Profile first, optimize later. Red/orange flame chart cells point to the component to look at — never guess the bottleneck.