React Uygulamalarında INP (Interaction to Next Paint) Optimizasyonu
Google, Mart 2024'te Core Web Vitals metriklerinde devrim niteliğinde bir değişiklik yaparak FID (First Input Delay) metriğini emekliye ayırdı ve yerine INP (Interaction to Next Paint) metriğini getirdi. Artık arama motoru sıralamalarınızda "sayfanın sadece ilk yüklendiğinde değil, tüm yaşam döngüsü boyunca" ne kadar tepkisel (responsive) olduğu ölçülüyor.
Kıdemli bir frontend mühendisi olarak, yüksek trafikli platformlarda (özellikle etkileşimi bol e-ticaret sitelerinde) INP optimizasyonu artık günlük rutininizin bir parçası olmalıdır.
INP Nedir ve FID'den Farkı Nedir?
- FID: Sadece kullanıcının sayfa ile ilk etkileşimini ölçerdi. İşleme süresini değil, sadece bekleme süresini hesaba katardı.
- INP: Kullanıcının sayfa ile olan tüm etkileşimlerini (tıklama, klavye girişi vb.) izler. Etkileşimin başlamasından, bir sonraki çerçevenin (paint) ekranda çizilmesine kadar geçen toplam süreyi (Gecikme + İşlem + Render) ölçer. Hedef değer 200 milisaniye ve altıdır.
React Uygulamalarında INP Neden Yüksek Çıkar?
React, varsayılan olarak senkron bir çalışma yapısına sahiptir. Bir state güncellendiğinde, React sanal DOM'u (Virtual DOM) hesaplar ve gerçek DOM'a uygular. Eğer bu işlem çok uzun sürerse (Long Task), tarayıcının ana iş parçacığı (Main Thread) bloke olur. Ana iş parçacığı bloke olduğunda, tarayıcı kullanıcının yeni tıklamalarına veya kaydırma (scroll) hareketlerine tepki veremez; site "donmuş" hissi yaratır.
Strateji 1: startTransition ve useDeferredValue ile Önceliklendirme
React 18 ile gelen Concurrent özellikler, INP optimizasyonu için en büyük silahımızdır. Ağır bir filtreleme veya arama işlemi yapıyorsanız, acil olmayan güncellemeleri erteleyebilirsiniz.
import { useState, useTransition } from "react";
export function ProductSearch() {
const [query, setQuery] = useState("");
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
// 1. Kullanıcının klavye girdisi acildir, hemen yansıtılır (INP skorunu korur)
setQuery(e.target.value);
// 2. Ağır filtreleme işlemi acil değildir, arka planda sıraya alınır
startTransition(() => {
performHeavyFiltering(e.target.value);
});
};
return (
<div>
<input type="text" value={query} onChange={handleChange} />
{isPending ? <Spinner /> : <ProductList query={query} />}
</div>
);
}