- Konu sahibi
- #1
React hydration hatası, sunucunun HTML olarak ürettiği ilk çıktı ile tarayıcıda React’ın ilk render sırasında üretmeye çalıştığı çıktının aynı olmaması nedeniyle oluşur. React mevcut sunucu HTML’sini yeniden kullanabilmek için bu iki çıktının eşleşmesini bekler. Tarih, rastgele sayı, tarayıcı API’si, kullanıcıya göre değişen veri veya sunucu ve istemcide farklı çalışan koşullu kodlar bu eşleşmeyi bozabilir.
SSR veya statik ön oluşturma kullanan uygulamalarda süreç kabaca şöyledir:
Sunucu ve istemci ilk render’da aynı metni, aynı eleman yapısını ve uyumlu özellikleri üretmelidir. Sadece
Sunucuda window’a doğrudan erişmek önce ReferenceError ile SSR’ı bozabilir; bu, oluşmuş iki HTML’nin uyuşmamasından farklı bir hatadır. typeof window kontrolüyle sunucuda bir dalı, tarayıcıda başka bir dalı render etmek ise hydration farkı oluşturabilir. CSR ile yalnız tarayıcıda başlayan her React uygulaması hydration yapmaz; bu tanı SSR/önceden üretilmiş HTML’nin hydrateRoot ile devralındığı akış içindir.
Aşağıdaki bileşen her render’da farklı sayı üretir. Sunucu örneğin
Değerin ilk HTML’de görünmesi gerekmiyorsa, başlangıç değerini sabit tutup rastgele üretimi istemci tarafındaki etkiye taşıyabilirsiniz:
Burada sunucu ve istemcinin ilk çıktısı
Aşağıdaki karar özeti, hangi yaklaşımın uygun olduğunu gösterir:
Hydration nasıl çalışır?
SSR veya statik ön oluşturma kullanan uygulamalarda süreç kabaca şöyledir:
- Sunucu, bileşeni çalıştırır ve tarayıcıya başlangıç HTML’sini gönderir.
- Tarayıcı bu HTML’yi ekranda gösterir.
- JavaScript paketi yüklendiğinde React aynı bileşeni istemcide ilk kez çalıştırır.
- React, istemci çıktısını mevcut HTML ile eşleştirerek olay dinleyicilerini ve bileşen davranışını bağlar.
Sunucu ve istemci ilk render’da aynı metni, aynı eleman yapısını ve uyumlu özellikleri üretmelidir. Sadece
useEffect sonrasında değişen değerler bu ilk karşılaştırmanın dışında kalır; ancak kullanıcının gördüğü ilk içerik önce sunucu çıktısıyla uyumlu olmalıdır.En yaygın nedenler
Math.random()veyaDate.now()gibi her çalıştırmada değişen değerleri JSX içinde doğrudan kullanmak.- Tarih ve sayı biçimlendirmesini sunucuda ve tarayıcıda farklı yerel ayarlarla yapmak.
window,document,localStorageveya ekran bilgisi gibi yalnızca tarayıcıda bulunan API’leri render sırasında okumak.- Çerez, oturum, kimlik doğrulama veya kullanıcı tercihlerinin sunucuya ve istemciye farklı ulaşması.
- Geçersiz HTML iç içeliği oluşturmak; örneğin bir
pelemanının içine uygun olmayan blok elemanları yerleştirmek. - Hydration başlamadan önce veya sırasında bir tarayıcı eklentisinin ya da üçüncü taraf kodun sunucu HTML’sini değiştirmesi.
Sunucuda window’a doğrudan erişmek önce ReferenceError ile SSR’ı bozabilir; bu, oluşmuş iki HTML’nin uyuşmamasından farklı bir hatadır. typeof window kontrolüyle sunucuda bir dalı, tarayıcıda başka bir dalı render etmek ise hydration farkı oluşturabilir. CSR ile yalnız tarayıcıda başlayan her React uygulaması hydration yapmaz; bu tanı SSR/önceden üretilmiş HTML’nin hydrateRoot ile devralındığı akış içindir.
Somut örnek ve doğru düzeltme
Aşağıdaki bileşen her render’da farklı sayı üretir. Sunucu örneğin
0.42, istemci ise 0.17 üretirse React aynı metni bulamaz:
Kod:
function RandomNumber() {
return <p>Numara: {Math.random()}</p>;
}
Değerin ilk HTML’de görünmesi gerekmiyorsa, başlangıç değerini sabit tutup rastgele üretimi istemci tarafındaki etkiye taşıyabilirsiniz:
Kod:
import { useEffect, useState } from 'react';
function RandomNumber() {
const [number, setNumber] = useState(null);
useEffect(() => {
setNumber(Math.random());
}, []);
return <p>Numara: {number ?? 'Hesaplanıyor...'}</p>;
}
Burada sunucu ve istemcinin ilk çıktısı
Hesaplanıyor... olur. useEffect sonrasında sayı gösterilir. Çalışma sonucu hata ortadan kalkıyor ve sayı yalnızca etki sonrasında görünüyorsa düzeltme doğru uygulanmıştır. Ancak rastgele değer SEO, paylaşılabilirlik veya sunucu tarafından üretilen içerik için önemliyse daha iyi çözüm, değeri sunucuda bir kez üretip istemciye prop olarak aktarmaktır.Hatanın kaynağını bulma ve düzeltme
- Hata mesajındaki bileşen ağacını ve farklı görünen metni belirleyin; doğrudan tüm hydration uyarısını gizlemeyin.
- İlgili render kodunda
Date,Math.random(),window,document,localStorageve kullanıcıya bağlı koşulları arayın. - İlk render’ı deterministik yapın: aynı başlangıç prop’larını, sabit bir placeholder’ı veya sunucudan aktarılan veriyi kullanın.
- Tarayıcıya özel işlemleri
useEffectiçine taşıyın. İlk çıktının sunucu ile istemcide yine aynı kaldığını kontrol edin. - Tarih ve sayı biçimlendirmesinde aynı veri ve açık biçimlendirme ayarlarını kullanın; mümkünse biçimlendirilmiş sonucu sunucudan gönderin.
- HTML elemanlarının doğru iç içe olduğunu doğrulayın ve üçüncü taraf bileşenleri geçici olarak kaldırarak farkın kaynağını izole edin.
- Düzeltmeden sonra üretim derlemesinde de test edin; yalnızca geliştirme ortamında kaybolan uyarıyı çözülmüş kabul etmeyin.
Aşağıdaki karar özeti, hangi yaklaşımın uygun olduğunu gösterir:
| Durum | İlk render yaklaşımı | Sonraki işlem |
|---|---|---|
| Rastgele veya anlık değer | Sabit placeholder veya sunucu değeri | İstemcide effect ile güncelle |
| Tarayıcı API’si gerekiyor | Tarayıcı yokmuş gibi aynı başlangıç çıktısını üret | API’yi effect içinde oku |
| Kullanıcıya özel veri | Veriyi sunucu ve istemci arasında aynı aktar | Eksikse yüklenme durumunu göster |
| HTML yapısı uyuşmuyor | Geçerli ve aynı eleman ağacını kur | Etkilenen bileşeni yeniden test et |
Kaynaklar
Sık sorulan sorular
Hydration uyarısını bastırmak sorunu çözer mi?
Hayır. suppressHydrationWarning kontrollü ve kaçınılmaz farklar için bir kaçış seçeneğidir; tek seviye derinlikte etkilidir ve farklı metni React’in otomatik düzelteceği garantisini vermez. Bastırma yalnızca belirli bir metnin bilerek farklı olması gibi kontrollü durumlarda düşünülebilir. Rastgele veri, yanlış veri aktarımı veya bozuk HTML varsa kök nedeni gizler ve arayüzün beklenmedik davranmasına yol açabilir.
Sadece bir tarih alanı hata veriyorsa ne kontrol edilmelidir?
Sunucunun ve tarayıcının aynı zaman dilimi, yerel ayar ve giriş verisini kullanıp kullanmadığını kontrol edin. En güvenlisi, ilk çıktıyı sunucuda biçimlendirip istemciye hazır metin olarak aktarmak veya ilk render’da sabit bir yüklenme metni göstermektir.