feat: added new blog
This commit is contained in:
@@ -0,0 +1,199 @@
|
|||||||
|
---
|
||||||
|
title: "Next.js'te Hydration Error: Nedir, Neden Olur ve Nasıl Çözülür?"
|
||||||
|
category: "Frontend"
|
||||||
|
date: "2026-07-18"
|
||||||
|
readTime: "8 min read"
|
||||||
|
author: "Poyraz Avsever"
|
||||||
|
slug: "nextjs-hydration-error-nedir-ve-nasil-cozulur"
|
||||||
|
excerpt: "Next.js projelerinde sıkça karşılaşılan Hydration Error (Rehidrasyon Hatası) nedir? Sunucu ve istemci arasındaki HTML uyumsuzlukları neden kaynaklanır ve bu hataları nasıl profesyonelce çözebiliriz?"
|
||||||
|
coverImage: "/blog/images/nextjs-hydration-error-cover.jpg"
|
||||||
|
canonicalUrl: "https://medium.com/@poyrazavsever/nextjs-hydration-error-nedir-ve-nasil-cozulur-hash"
|
||||||
|
lang: "tr"
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Next.js ile uygulama geliştirirken ekranın ortasında aniden beliren o kırmızı hata mesajını hepimiz görmüşüzdür. Kendi projelerimde de bu durumla sık sık karşılaşınca "Her şeyi doğru yazdım neden çalışmıyor" demek yerine işin temeline inip bu konuyu detaylıca araştırmak istedim.
|
||||||
|
|
||||||
|
Bu hatanın adını hepimiz biliyoruz: Hydration Error. Ancak sadece ezbere çözümler bulmak yerine sistemin nasıl çalıştığını anlamak çok daha faydalı. Çünkü hatanın arkasındaki mantığı kavradığımızda onu çözmek çocuk oyuncağı haline geliyor.
|
||||||
|
|
||||||
|
Hadi önce işin mutfağına girelim.
|
||||||
|
|
||||||
|
### Pre-rendering: Cansız Bir HTML İskeleti
|
||||||
|
|
||||||
|
Next.js'i klasik React uygulamalarından ayıran en büyük özellik sayfaları tarayıcıya göndermeden önce sunucuda oluşturmasıdır. Buna Pre-rendering diyoruz.
|
||||||
|
|
||||||
|
Kullanıcı sitenize girdiğinde Next.js ona içi boş bir sayfa yerine tamamen dolu ve okunabilir bir HTML sunar. Bu sayede kullanıcılar içeriği anında görür. Buraya kadar her şey harika. Fakat sunucudan gelen bu HTML dosyası çok hızlı olsa da henüz cansız bir yapıdadır. Butonlara tıklayamazsınız veya menüleri açamazsınız çünkü React henüz devrede değildir.
|
||||||
|
|
||||||
|
### Hydration: Statik Koda Su Katmak
|
||||||
|
|
||||||
|
İşte tam bu noktada Hydration süreci başlıyor. Tarayıcı o statik HTML'i ekrana çizdikten hemen sonra arka planda React kodlarını indirip çalıştırıyor.
|
||||||
|
|
||||||
|
React uyanıp tarayıcıdaki bu cansız HTML yapısını inceliyor. Ardından kendi hafızasındaki yapı ile eşleştirip butonlara, formlara ve linklere gerekli işlevleri bağlayarak sayfayı interaktif hale getiriyor. Bu süreci kurumuş bir bitkiye su verip onu tekrar canlandırmaya benzetebilirsiniz. Zaten hydrate kelimesi de tam olarak buradan geliyor.
|
||||||
|
|
||||||
|
Sistem kulağa çok kusursuz geliyor ama bazen işler ters gidiyor ve konsolda şu mesajla karşılaşıyoruz:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Error: Text content does not match server-rendered HTML.
|
||||||
|
```
|
||||||
|
|
||||||
|
Peki sistem bu kadar mantıklıyken React neden aniden hata verip işlemi durduruyor? Gelin şimdi bu sorunun temeline ve yapılan en yaygın hatalara birlikte bakalım.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Asıl Problem: Uyuşmazlık (Mismatch)
|
||||||
|
|
||||||
|
React tarayıcıda uyandığında aslında çok net bir beklentisi vardır. Sunucunun hazırlayıp gönderdiği HTML yapısı ile kendi hafızasında oluşturduğu HTML yapısı birebir aynı olmalıdır. En ufak bir farklılık bile kabul edilmez.
|
||||||
|
|
||||||
|
Diyelim ki sunucu ekrana "A" yazdırdı. React tarayıcıda çalışıp "Benim buraya B yazmam gerekiyor" derse işler o an karışır. Çünkü React mevcut HTML'i değiştirmek için değil sadece devralmak için tasarlanmıştır. Devralacağı yapı beklediğinden farklı çıkarsa güvenlik ve tutarlılık adına işlemi durdurur ve o uyuşmazlık hatasını fırlatır.
|
||||||
|
|
||||||
|
Aslında React bize basitçe şunu söylüyor: "Sunucudan gelen taslak ile senin tarayıcıda çizmemi istediğin taslak birbirini tutmuyor. Hangisine güveneceğimi bilemiyorum."
|
||||||
|
|
||||||
|
Peki bu iki yapı neden birbirinden farklı çıkıyor... Nerelerde hata yapıyoruz... Gelin en sık karşılaştığımız senaryolara bakalım.
|
||||||
|
|
||||||
|
## Hydration Hatasının En Yaygın 4 Sebebi
|
||||||
|
|
||||||
|
Bu uyuşmazlığın genelde çok temel birkaç sebebi oluyor. Karmaşık teoriler yerine basit kod örnekleriyle ilerleyelim.
|
||||||
|
|
||||||
|
### 1. Geçersiz HTML İç İçe Geçmeleri
|
||||||
|
|
||||||
|
HTML yazarken bazen kuralları esnetebiliyoruz ama React bu konuda oldukça hassas. Örneğin bir paragraf etiketinin içine yanlışlıkla bir div koyduğunuzu düşünün.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p>
|
||||||
|
Merhaba
|
||||||
|
<div>Dünya</div>
|
||||||
|
</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
Sunucu bunu aynen oluşturup tarayıcıya gönderir. Fakat tarayıcılar hatalı HTML yapılarını gördüklerinde sayfayı düzgün göstermek için yapıyı otomatik olarak düzeltirler. Yani o div etiketini paragrafın dışına atarlar. React çalışıp DOM'a baktığında sunucudan gelen yapı ile tarayıcının kendi kendine düzelttiği yapının farklı olduğunu görür ve hatayı verir.
|
||||||
|
|
||||||
|
### 2. Sadece Tarayıcıya Özel Objeleri Kullanmak
|
||||||
|
|
||||||
|
En sık düştüğümüz tuzaklardan biri budur. Geliştirme yaparken ekran genişliğini veya sadece tarayıcıda olan bir veriyi okumak isteyebiliriz.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function MyComponent() {
|
||||||
|
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
|
||||||
|
|
||||||
|
return <div>{isMobile ? 'Mobil Görünüm' : 'Masaüstü Görünüm'}</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Sunucu tarafında yani Node.js ortamında window objesi yoktur. Bu yüzden sunucu bu kodu genelde hep "Masaüstü Görünüm" olarak çalıştırıp gönderir. Ama kodu bir telefonda açtığınızda React tarayıcıda çalışırken window objesini bulur ve "Mobil Görünüm" sonucunu üretir. Sunucudan gelen metin ile tarayıcıdaki metin uyuşmadığı için hydration hatası kaçınılmaz olur.
|
||||||
|
|
||||||
|
### 3. Rastgele Değerler ve Zamanlar
|
||||||
|
|
||||||
|
Her çalıştığında farklı sonuç üreten fonksiyonlar da bu sürecin düşmanıdır.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function RandomNumber() {
|
||||||
|
const number = Math.random()
|
||||||
|
return <div>Şanslı numaranız: {number}</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Sunucu HTML'i oluştururken rastgele bir sayı üretir örneğin 0.5 diyelim. Tarayıcı sayfayı yükleyip React'i çalıştırdığında bu fonksiyon tekrar tetiklenir ve bu kez farklı bir sayı üretir. İki sonuç birbirinden farklı olduğu için sistem yine hata verir. Aynı durum ekrana anlık tarihi veya saati yazdırırken de yaşanır.
|
||||||
|
|
||||||
|
### 4. Tarayıcı Eklentileri
|
||||||
|
|
||||||
|
Bazen kodunuz tamamen kusursuzdur ama sayfayı yenilediğinizde yine bu hatayı alırsınız. Bunun sebebi Grammarly veya otomatik çeviri yapan tarayıcı eklentileri olabilir. Bu eklentiler sayfa yüklenir yüklenmez HTML yapısına dışarıdan müdahale edip kendi etiketlerini eklerler. React uyanıp HTML'e baktığında kendi ürettiği yapının eklentiler tarafından değiştirildiğini fark eder ve işlemi durdurur.
|
||||||
|
|
||||||
|
Sorunun kaynağını ve nedenlerini anladığımıza göre artık en keyifli kısma yani çözüm yollarına geçebiliriz.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hatayı Çözümleme Stratejileri (Nasıl Çözeriz?)
|
||||||
|
|
||||||
|
Hatanın nedenlerini ve React'in nasıl düşündüğünü kavradık. Peki bu sorunu kalıcı olarak nasıl çözeceğiz. İhtiyacınıza ve senaryonuza göre kullanabileceğiniz en etkili üç yöntemi inceleyelim.
|
||||||
|
|
||||||
|
### Yöntem 1: useEffect ile Render'ı Bekletmek (Mounted State)
|
||||||
|
|
||||||
|
Eğer uygulamanızda `window` objesine veya sadece tarayıcıda çalışan bir değere ihtiyacınız varsa en güvenli yol budur.
|
||||||
|
|
||||||
|
React'te `useEffect` hook'u sadece tarayıcıda (istemci tarafında) çalışır, sunucuda çalışmaz. Biz de bu bilgiyi kullanarak bir state oluşturabilir ve bileşenimizin gerçekten tarayıcıda yüklenip yüklenmediğini (mount olup olmadığını) kontrol edebiliriz.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
function ClientOnlyComponent() {
|
||||||
|
const [isMounted, setIsMounted] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Bu kod sadece tarayıcıda çalışacak
|
||||||
|
setIsMounted(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Eğer henüz tarayıcıda değilsek hiçbir şey veya bir yükleniyor ekranı göster
|
||||||
|
if (!isMounted) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Artık güvenle window objesini kullanabiliriz
|
||||||
|
return <div>Ekran genişliği: {window.innerWidth}</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bu yöntem sayesinde sunucu tarafı `null` döner, tarayıcı da ilk render aşamasında `null` döner. İkisi birbiriyle eşleştiği için hata almayız. Hemen ardından `useEffect` devreye girer ve gerçek içeriğimizi ekrana basar.
|
||||||
|
|
||||||
|
### Yöntem 2: Next.js Dynamic Imports (SSR'ı Kapatmak)
|
||||||
|
|
||||||
|
Eğer elinizde çok büyük bir bileşen varsa (örneğin bir harita kütüphanesi veya karmaşık bir grafik) ve bu bileşenin sunucuda render edilmesini hiç istemiyorsanız Next.js'in sunduğu harika bir özellik var.
|
||||||
|
|
||||||
|
`next/dynamic` kullanarak bir bileşeni projeye dahil ederken `{ ssr: false }` ayarını verebilirsiniz. Bu sayede Next.js o bileşeni sunucu tarafında tamamen yok sayar.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
|
||||||
|
// Bileşeni içe aktarırken ssr özelliğini kapatıyoruz
|
||||||
|
const NoSSRComponent = dynamic(() => import('../components/HeavyMap'), {
|
||||||
|
ssr: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
function MyPage() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>İletişim Sayfası</h1>
|
||||||
|
<NoSSRComponent />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bu yöntem hem hydration hatalarını kökünden çözer hem de gereksiz yere sunucuyu yormadığınız için performans artışı sağlar.
|
||||||
|
|
||||||
|
### Yöntem 3: Uyuşmazlığı Görmezden Gelmek (suppressHydrationWarning)
|
||||||
|
|
||||||
|
Bazen uyuşmazlık olduğunu biliriz ama bunun tamamen zararsız olduğundan eminizdir. Örneğin ekrana anlık saati yazdırıyorsunuzdur ve sunucudaki saat ile kullanıcının saatinin birkaç saniye farklı olması çok doğaldır.
|
||||||
|
|
||||||
|
Böyle durumlarda React'e "Ben ne yaptığımı biliyorum, bu HTML etiketindeki uyuşmazlığı görmezden gel" diyebiliriz.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function CurrentTime() {
|
||||||
|
const time = new Date().toLocaleTimeString()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div suppressHydrationWarning>
|
||||||
|
Şu anki saat: {time}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bu özelliği ilgili HTML etiketine eklediğinizde React o satır için hata fırlatmayı bırakır. Ancak burada çok önemli bir detay var. Bu özelliği sadece metin farklılıkları için kullanmalısınız. Eğer HTML yapısında bir farklılık varsa (örneğin fazladan bir div eklendiyse) bu özellik işe yaramaz ve uygulamanız yine hata verir. O yüzden bunu sadece son çare olarak ve dikkatlice kullanmakta fayda var.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sonuç ve En İyi Yaklaşımlar
|
||||||
|
|
||||||
|
Hydration hatası ilk başta çok korkutucu bir hata ekranı gibi görünse de aslında React'in uygulamamızı tutarsızlıklardan koruma yöntemidir. Sistemin nasıl çalıştığını anladıktan sonra bu hataları çözmek oldukça kolay bir hale geliyor.
|
||||||
|
|
||||||
|
Gelecekte bu hatalarla daha az karşılaşmak için şu üç temel alışkanlığı edinmek hayat kurtarıyor:
|
||||||
|
|
||||||
|
* **Geçerli HTML Yazın:** HTML kurallarına her zaman sadık kalın. Bir span etiketinin içine div koymak gibi hatalı iç içe geçmelerden kaçının.
|
||||||
|
* **Tarayıcı Verilerini Doğru Yönetin:** window, document veya localStorage gibi sadece tarayıcıya özgü yapıları kullanırken bileşeninizin sunucuda nasıl davranacağını her zaman hesaba katın.
|
||||||
|
* **Doğru Aracı Seçin:** Karşınıza bir uyuşmazlık çıktığında ilk tercihiniz genelde useEffect ile bekletmek veya dynamic import ile sunucu render işlemini kapatmak olsun. suppressHydrationWarning özelliğini ise sadece saat veya rastgele sayı gibi ufak metin farklılıklarında kullanın.
|
||||||
|
|
||||||
|
Umarım bu yazı projelerinizde karşınıza çıkan o meşhur kırmızı hata ekranlarını daha stressiz bir şekilde çözmenize yardımcı olur. Geliştirme yaparken işin arka planındaki bu temel mantığı aklınızda bulundurmak size bolca zaman kazandıracaktır.
|
||||||
|
|
||||||
|
Bir sonraki yazıda görüşmek üzere.
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
---
|
||||||
|
title: "Hydration Error in Next.js: What Is It, Why Does It Happen, and How Is It Fixed?"
|
||||||
|
category: "Frontend"
|
||||||
|
date: "2026-07-18"
|
||||||
|
readTime: "8 min read"
|
||||||
|
author: "Poyraz Avsever"
|
||||||
|
slug: "nextjs-hydration-error-what-is-it-and-how-is-it-fixed"
|
||||||
|
excerpt: "What is the Hydration Error, which is frequently encountered in Next.js projects? What causes HTML mismatches between the server and the client, and how can we solve these errors professionally?"
|
||||||
|
coverImage: "/blog/images/nextjs-hydration-error-cover.jpg"
|
||||||
|
canonicalUrl: "https://medium.com/@poyrazavsever/nextjs-hydration-error-what-is-it-and-how-is-it-fixed-hash"
|
||||||
|
lang: "en"
|
||||||
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
While developing an application with Next.js, we have all probably seen that red error message suddenly appearing in the middle of the screen. When I encountered this situation often in my own projects as well, instead of saying "I wrote everything correctly, why is it not working", I wanted to get to the root of the matter and research this topic in detail.
|
||||||
|
|
||||||
|
We all know the name of this error: Hydration Error. However, instead of only finding memorized solutions, understanding how the system works is much more useful. Because when we grasp the logic behind the error, solving it becomes child's play.
|
||||||
|
|
||||||
|
Let's first go into the kitchen of the work.
|
||||||
|
|
||||||
|
### Pre-rendering: A Lifeless HTML Skeleton
|
||||||
|
|
||||||
|
The biggest feature that separates Next.js from classic React applications is that it creates pages on the server before sending them to the browser. We call this Pre-rendering.
|
||||||
|
|
||||||
|
When a user enters your site, Next.js presents them with a completely filled and readable HTML instead of an empty page. Thanks to this, users see the content instantly. Everything is great up to this point. But although this HTML file coming from the server is very fast, it is still a lifeless structure. You cannot click buttons or open menus because React is not in play yet.
|
||||||
|
|
||||||
|
### Hydration: Adding Water to Static Code
|
||||||
|
|
||||||
|
This is exactly where the Hydration process begins. Right after the browser draws that static HTML on the screen, it downloads and runs the React code in the background.
|
||||||
|
|
||||||
|
React wakes up and examines this lifeless HTML structure in the browser. Then, by matching it with the structure in its own memory and connecting the necessary functions to buttons, forms, and links, it makes the page interactive. You can compare this process to watering a dried plant and bringing it back to life. The word hydrate already comes exactly from here.
|
||||||
|
|
||||||
|
The system sounds very flawless, but sometimes things go wrong and we encounter this message in the console:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Error: Text content does not match server-rendered HTML.
|
||||||
|
```
|
||||||
|
|
||||||
|
So while the system is this logical, why does React suddenly give an error and stop the process? Now let's look together at the root of this problem and the most common mistakes made.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The Main Problem: Mismatch
|
||||||
|
|
||||||
|
When React wakes up in the browser, it actually has a very clear expectation. The HTML structure prepared and sent by the server and the HTML structure it creates in its own memory must be exactly the same. Even the slightest difference is not accepted.
|
||||||
|
|
||||||
|
Let's say the server printed "A" on the screen. If React runs in the browser and says "I need to write B here", things get mixed up at that moment. Because React is designed not to change the existing HTML, but only to take it over. If the structure it will take over turns out to be different from what it expects, it stops the process in the name of security and consistency and throws that mismatch error.
|
||||||
|
|
||||||
|
Actually, React is simply telling us this: "The draft coming from the server and the draft you want me to draw in the browser do not match. I do not know which one to trust."
|
||||||
|
|
||||||
|
So why do these two structures turn out different from each other... Where do we make mistakes... Let's look at the scenarios we encounter most often.
|
||||||
|
|
||||||
|
## The 4 Most Common Causes of Hydration Error
|
||||||
|
|
||||||
|
This mismatch generally has a few very basic causes. Instead of complex theories, let's proceed with simple code examples.
|
||||||
|
|
||||||
|
### 1. Invalid HTML Nesting
|
||||||
|
|
||||||
|
While writing HTML, sometimes we can stretch the rules, but React is quite sensitive about this. For example, imagine that you accidentally put a div inside a paragraph tag.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p>
|
||||||
|
Hello
|
||||||
|
<div>World</div>
|
||||||
|
</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
The server creates this exactly as it is and sends it to the browser. But when browsers see faulty HTML structures, they automatically fix the structure to display the page properly. In other words, they throw that div tag outside the paragraph. When React runs and looks at the DOM, it sees that the structure coming from the server and the structure the browser fixed on its own are different, and it gives the error.
|
||||||
|
|
||||||
|
### 2. Using Browser-Specific Objects Only
|
||||||
|
|
||||||
|
This is one of the traps we fall into most often. While developing, we may want to read the screen width or a piece of data that exists only in the browser.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function MyComponent() {
|
||||||
|
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
|
||||||
|
|
||||||
|
return <div>{isMobile ? 'Mobile View' : 'Desktop View'}</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
On the server side, that is, in the Node.js environment, there is no window object. That is why the server generally runs and sends this code as "Desktop View". But when you open the code on a phone, React finds the window object while running in the browser and produces the "Mobile View" result. Since the text coming from the server and the text in the browser do not match, the hydration error becomes inevitable.
|
||||||
|
|
||||||
|
### 3. Random Values and Times
|
||||||
|
|
||||||
|
Functions that produce different results each time they run are also enemies of this process.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function RandomNumber() {
|
||||||
|
const number = Math.random()
|
||||||
|
return <div>Your lucky number: {number}</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
While creating the HTML, the server generates a random number, for example let's say 0.5. When the browser loads the page and runs React, this function is triggered again and this time it generates a different number. Since the two results are different from each other, the system gives an error again. The same situation also happens when printing the current date or time on the screen.
|
||||||
|
|
||||||
|
### 4. Browser Extensions
|
||||||
|
|
||||||
|
Sometimes your code is completely flawless, but when you refresh the page, you still get this error. The reason for this may be browser extensions such as Grammarly or automatic translation tools. As soon as the page loads, these extensions interfere with the HTML structure from the outside and add their own tags. When React wakes up and looks at the HTML, it notices that the structure it produced has been changed by extensions and stops the process.
|
||||||
|
|
||||||
|
Now that we understand the source of the problem and its reasons, we can move on to the most enjoyable part, namely the solution methods.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error Solving Strategies (How Do We Solve It?)
|
||||||
|
|
||||||
|
We understood the reasons for the error and how React thinks. So how will we solve this problem permanently. Let's examine the three most effective methods you can use according to your need and scenario.
|
||||||
|
|
||||||
|
### Method 1: Delaying Render with useEffect (Mounted State)
|
||||||
|
|
||||||
|
If you need the `window` object or a value that works only in the browser in your application, this is the safest way.
|
||||||
|
|
||||||
|
In React, the `useEffect` hook runs only in the browser (on the client side), it does not run on the server. We can use this information to create a state and check whether our component has really loaded in the browser (whether it has mounted or not).
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
function ClientOnlyComponent() {
|
||||||
|
const [isMounted, setIsMounted] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// This code will run only in the browser
|
||||||
|
setIsMounted(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// If we are not in the browser yet, show nothing or a loading screen
|
||||||
|
if (!isMounted) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can safely use the window object
|
||||||
|
return <div>Screen width: {window.innerWidth}</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Thanks to this method, the server side returns `null`, and the browser also returns `null` during the first render stage. Since the two match each other, we do not get an error. Immediately afterward, `useEffect` comes into play and prints our real content to the screen.
|
||||||
|
|
||||||
|
### Method 2: Next.js Dynamic Imports (Turning Off SSR)
|
||||||
|
|
||||||
|
If you have a very large component in your hands (for example a map library or a complex chart) and you do not want this component to be rendered on the server at all, there is a great feature offered by Next.js.
|
||||||
|
|
||||||
|
By using `next/dynamic`, you can give the `{ ssr: false }` setting while including a component in the project. Thanks to this, Next.js completely ignores that component on the server side.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
|
||||||
|
// We turn off the ssr feature while importing the component
|
||||||
|
const NoSSRComponent = dynamic(() => import('../components/HeavyMap'), {
|
||||||
|
ssr: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
function MyPage() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Contact Page</h1>
|
||||||
|
<NoSSRComponent />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This method both solves hydration errors from the root and provides a performance increase because you do not tire the server unnecessarily.
|
||||||
|
|
||||||
|
### Method 3: Ignoring the Mismatch (suppressHydrationWarning)
|
||||||
|
|
||||||
|
Sometimes we know there is a mismatch, but we are sure that it is completely harmless. For example, you may be printing the current time on the screen, and it is very natural for the time on the server and the user's time to differ by a few seconds.
|
||||||
|
|
||||||
|
In such cases, we can tell React, "I know what I am doing, ignore the mismatch in this HTML tag."
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function CurrentTime() {
|
||||||
|
const time = new Date().toLocaleTimeString()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div suppressHydrationWarning>
|
||||||
|
Current time: {time}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When you add this feature to the relevant HTML tag, React stops throwing an error for that line. However, there is a very important detail here. You should use this feature only for text differences. If there is a difference in the HTML structure (for example, if an extra div has been added), this feature will not work and your application will still give an error. Therefore, it is useful to use this only as a last resort and carefully.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Conclusion and Best Approaches
|
||||||
|
|
||||||
|
Although the hydration error looks like a very scary error screen at first, it is actually React's method of protecting our application from inconsistencies. After understanding how the system works, solving these errors becomes quite easy.
|
||||||
|
|
||||||
|
To encounter these errors less in the future, acquiring these three basic habits is a lifesaver:
|
||||||
|
|
||||||
|
* **Write Valid HTML:** Always stay loyal to HTML rules. Avoid faulty nestings such as putting a div inside a span tag.
|
||||||
|
* **Manage Browser Data Correctly:** When using browser-specific structures such as window, document, or localStorage, always take into account how your component will behave on the server.
|
||||||
|
* **Choose the Right Tool:** When you encounter a mismatch, your first choice should generally be delaying with useEffect or turning off server rendering with dynamic import. Use the suppressHydrationWarning feature only for small text differences such as time or random numbers.
|
||||||
|
|
||||||
|
I hope this article helps you solve those famous red error screens you encounter in your projects in a less stressful way. Keeping this basic logic in the background of the work in mind while developing will save you plenty of time.
|
||||||
|
|
||||||
|
See you in the next article.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
Reference in New Issue
Block a user