دیباگ INP در اپهای React از Field Data تا Profiler
INP فقط یک عدد Lighthouse نیست. اگر کلیک، تایپ یا بازکردن یک منو برای کاربر دیر پاسخ میدهد، باید مسیر کامل interaction را بررسی کنید: event handler، محاسبات JavaScript، render و paint.
1. از Field Data شروع کنید
قبل از بهینهسازی، مشخص کنید مشکل واقعاً برای کاربران رخ میدهد یا فقط در یک تست مصنوعی دیده شده است. دادههای واقعی را بر اساس route، device و interaction دستهبندی کنید. هدف این است که یک interaction مشخص برای بازتولید داشته باشید، نه اینکه کل اپ را «سریعتر» کنید.
2. interaction کند را بازتولید کنید
در DevTools Performance یک trace بگیرید و همان رفتار را تکرار کنید. به Long Taskها، handlerهای طولانی و فاصله بین input و paint بعدی توجه کنید.
click
-> event handler
-> state update
-> React render
-> style/layout
-> paint
اگر بخش اصلی زمان قبل از render مصرف میشود، memo کردن کامپوننتها احتمالاً درمان مسئله نیست.
3. handler را سبک نگه دارید
کارهای مستقل از پاسخ فوری UI را از مسیر interaction خارج کنید. parsing بزرگ، sort سنگین یا تبدیل داده حجیم نباید بدون دلیل داخل handler اجرا شود.
function handleSelect(id: string) {
setSelectedId(id)
// کار سنگین و غیرضروری را اینجا همزمان اجرا نکنید.
}
برای محاسبات CPU-heavy ابتدا کاهش حجم کار، cache کردن نتیجه معتبر یا انتقال کار به worker را بررسی کنید.
4. React Profiler را برای render بررسی کنید
اگر trace نشان میدهد render سهم قابلتوجهی دارد، Profiler را باز کنید و ببینید کدام subtree دوباره render شده است و چرا. memo، useMemo و useCallback ابزار هدفمند هستند، نه تنظیمات پیشفرض.
نشانههای رایج:
- Context بزرگی که با هر تغییر مصرفکنندههای زیادی را render میکند؛
- object یا callback جدیدی که memoization موجود را بیاثر میکند؛
- state بالاتر از سطح مالک واقعی آن نگهداری میشود؛
- list بزرگ بدون virtualization رندر میشود.
5. Transition را فقط برای کار non-urgent استفاده کنید
اگر یک update برای feedback فوری لازم نیست، میتوان آن را در transition قرار داد تا updateهای فوری اولویت داشته باشند.
import { startTransition } from "react"
function handleSearch(value: string) {
setInput(value)
startTransition(() => {
setFilter(value)
})
}
Transition محاسبه سنگین JavaScript را جادویی سریع نمیکند؛ فقط scheduling updateهای React را تغییر میدهد.
6. بعد از هر تغییر دوباره اندازه بگیرید
هر optimization باید یک فرضیه داشته باشد: «این handler 80ms کار sync دارد» یا «این Context باعث render شدن 300 row میشود». بعد از تغییر همان interaction را دوباره trace کنید و نتیجه را با baseline مقایسه کنید.
چکلیست نهایی
- interaction واقعی و route مشکلدار را پیدا کنید؛
- Performance trace بگیرید؛
- زمان handler، render و layout/paint را از هم جدا کنید؛
- بزرگترین هزینه را اصلاح کنید؛
- Profiler را فقط وقتی render مشکوک است وارد کنید؛
- روی دستگاه ضعیفتر و Field Data دوباره اعتبارسنجی کنید.
بهینهسازی INP زمانی قابل اعتماد است که از یک interaction واقعی شروع شود و با اندازهگیری همان interaction تمام شود.