Bir Next.js 16 projesi geliştirirken, optimistik arayüzler kullanmanın sunduğu hızlı yanıt avantajından faydalanmak cazip gelebilir. Ancak kullanıcıların gerçek davranışlarını simüle etmek önemlidir. Basit bir görev listesinde useOptimistic kancasını kullanarak onay kutusunun anında yanıt vermesini sağladığınızda, her şey kusursuz görünebilir. Peki ya kullanıcı o onay kutusuna beş kez peş peşe tıklarsa?
Bu senaryoyu test ettiğimde, ilk etapta her şey yolundaydı: onay kutusu anında değişti, bekleme ekranı ya da gecikme olmadı. Ancak arka planda beş adet eşzamanlı istek sunucuya gönderilmişti. Her biri aynı boolean değeri değiştirmeye çalışıyordu ve sonuçlar rastgele bir sırada geri dönüyordu. Ne hata mesajı ne de çökme yaşandı — sadece arayüz, sunucudaki gerçek durumla senkronize olmadı. Bu, optimistik arayüzlerin en sık karşılaşılan ve gözden kaçabilen hatalarından biri.
Optimistik UI’nin Temel Kuralı: Her Satırın Kendi Durumunu Yönetmesi
Bu sorunun çözümü, aslında yeni bir yöntem değil. Formlardaki gönderim düğmesini beklerken devre dışı bırakmakla aynı prensibe dayanıyor. Her satırın kendi istek durumunu takip etmesi ve ilgili öğe için bir istek beklerken kullanıcı etkileşimini engellemesi gerekiyor. Bu şekilde, ikinci bir tıklama anında gerçekleşen gereksiz istekler önlenmiş olur.
Aşağıdaki kod parçası, bu yaklaşımı uygulamanın basit bir yolunu gösteriyor:
const [pendingId, setPendingId] = useState<string | null>(null);
function handleToggle(id: string) {
setPendingId(id);
startTransition(async () => {
setOptimisticTask(id);
try {
await toggleTask(id);
} finally {
setPendingId(null);
}
});
}<input
type="checkbox"
checked={task.completed}
disabled={pendingId === task.id}
onChange={() => handleToggle(task.id)}
/>Bu yapıda, her satır kendi pendingId durumunu takip eder. Bir öğe için istek devam ederken, ilgili onay kutusu devre dışı bırakılır ve ikinci bir tıklama engellenir. Beş kez hızlı tıklama yaptığınızda, sadece bir istek sunucuya gönderilir — gereksiz yükten ve senkronizasyon sorunlarından kaçınılmış olur.
Optimistik Güncellemenin Geri Alınması: Gereksiz Durumlarda Karmaşa
Optimistik güncelleme sırasında bir hata oluşursa ne olur? Pek çok örnek kodda, başarısızlık durumunda geçici durumu eski haline döndürmek için ikinci bir setOptimisticTask çağrısı yapılır. Ancak bu yaklaşım, basit bir görev durumunun değiştirilmesi gibi senaryolarda gereksizdir.
useOptimistic kancası, geçici bir değer katmanı sağlar ve bu katman, geçiş süreci tamamlandığında otomatik olarak kaldırılır. İster başarılı ister başarısız olsun, React gerçek duruma geri döner. Eğer gerçek durum hiç değişmediyse — çünkü istek başarısız oldu ve yeniden veri çekilmedi — onay kutusu otomatik olarak eski haline döner. İkinci bir durum güncellemesine gerek yoktur.
Ancak bu otomatik geri alma mekanizmasının istisnası vardır: optimistik değer, sunucudan henüz onay almamış yeni bir öğe olduğunda. Örneğin, veritabanı tarafından atanan gerçek bir kimliği olmayan yeni bir yorum eklenirken, geçici olarak eklenmiş bir öğenin durumunu geri almak için yerel olarak kaydedilmiş bir kopyaya ihtiyaç duyarsınız. Bu durumda, başarısız bir ekleme işlemi bayrağı geri almaz — sadece istemcide var olan bir öğeyi kaldırmanız gerekir. Bir görev durumunun değiştirilmesi bu sorunu yaşamaz, çünkü ilgili değer zaten sunucuda mevcuttur.
Önbellek Geçersizleştirme: Hangi Yöntem En Doğru?
Görev durumunun başarılı bir şekilde değiştirilmesinden sonra, önbelleğin nasıl geçersizleştirileceğine karar vermek önemlidir. Next.js 16, üç farklı geçersizleştirme yöntemi sunar:
revalidatePath: Belirli bir yolun önbelleğini geçersiz kılar.revalidateTag: Aynı etiketi paylaşan tüm önbellek girişlerini geçersiz kılar ve "stale-while-revalidate" davranışı uygular.updateTag(yalnızca Sunucu Eylemleri): Bir etiketi hemen geçersiz kılar, böylece kullanıcının mevcut sayfasında yazının anında yansıtılmasını sağlar.
Eğer kullanıcı, tıkladığı onay kutusuna odaklanıyorsa, updateTag en uygun seçenektir. Aynı görevin sayımını gösteren ve kullanıcının gerçek zamanlı olarak izlemediği bir yan panel varsa, aynı etiketi revalidateTag ile geçersiz kılmak, tüm siteyi tek bir yazı nedeniyle bloke etmekten kaçınır.
Next.js 16’nın yeni sürümlerinde dikkat edilmesi gereken bir detay: revalidateTag artık ikinci bir argüman gerektiriyor.
revalidateTag("tasks", "max"); // Next.js 16+ için önerilen kullanımEski kullanım olan revalidateTag("tasks") artık geçersizdir ve TypeScript hatasına neden olur.
Hata Sınırları: Veri Getirme Hatalarına Özel Çözüm
Son olarak, istek başarısız olduğunda — bağlantı sorunu gibi teknik bir hata — ne olacağını düşünmek önemlidir. Next.js belgeleri, startTransition içinde oluşan hataların hata sınırlarına (error.tsx) kadar yükseldiğini açıkça belirtir. Ancak daha yeni bir detay, yalnızca Next.js 16.2 ve üstü sürümlerde mevcuttur: error.tsx, unstable_retry adlı yeni bir kurtarma prop’u içerir. Bu prop, daha eski olan reset prop’undan farklıdır.
reset: Hata ekranını siler ve aynı çocuk bileşenlerini eski halleriyle yeniden render eder. Ancak bu, altta yatan verilerin yeniden yüklenmesini sağlamaz. Eğer veri hiç yüklenemediyse, aynı bozuk ekranı yeniden gösterir.unstable_retry: Sunucuya geri giderek segmenti taze bir şekilde yeniden render eder. Bu, özellikle veri getirme kaynaklı bir hatada gereklidir.
Aşağıdaki örnek, bu farkı göstermektedir:
export default function TaskListError({
error,
unstable_retry,
}: {
error: Error & { digest?: string };
unstable_retry: () => void;
}) {
return (
<div role="alert">
<p>Bir şeyler ters gitti.</p>
<button onClick={unstable_retry}>Tekrar Dene</button>
</div>
);
}Optimistik arayüzler, kullanıcı deneyimini önemli ölçüde iyileştirebilir, ancak arka plandaki durum yönetimine dikkat etmek kritik önem taşır. Küçük testler ve dikkatli durum takibi, geliştiricilerin bu güçlü aracı güvenle kullanmalarını sağlar.
Yapay zeka özeti
Next.js 16 projelerinde optimistik UI kullanırken ortaya çıkan gizli senkronizasyon hatalarını ve çözüm yollarını keşfedin. Kullanıcı hızlı tıklamalarıyla nasıl başa çıkılır?