Hydration failed в Next.js: почему возникает ошибка и как её исправить

mr. Cooper 4 дня назад Веб-разработка
Hydration failed в Next.js: почему возникает ошибка и как её исправить

Ошибка Hydration failed because the initial UI does not match - одна из самых частых проблем в Next.js.

Обычно она появляется, когда HTML, сгенерированный на сервере, отличается от того, что React пытается отрендерить в браузере.

Проще говоря:

  • сервер отдал один HTML,

  • клиент сгенерировал другой,

  • React обнаружил несовпадение,

  • hydration ломается.

Как выглядит ошибка

Hydration failed because the initial UI does not match what was rendered on the server

Иногда дополнительно появляются:

  • Text content does not match

  • Expected server HTML to contain

  • Hydration mismatch

Почему возникает hydration error

1. Использование window или document

Это самая частая причина.

Неправильно:

export default function Page() {
  const width = window.innerWidth

  return <div>{width}</div>
}

На сервере window не существует.

Правильно:

"use client"

import { useEffect, useState } from "react"

export default function Page() {
  const [width, setWidth] = useState(0)

  useEffect(() => {
    setWidth(window.innerWidth)
  }, [])

  return <div>{width}</div>
}

2. Разный контент на сервере и клиенте

Например:

<div>{Date.now()}</div>

Сервер и браузер генерируют разное время.

Решение:

Перенеси данные в useEffect.

"use client"

import { useEffect, useState } from "react"

export default function Time() {
  const [time, setTime] = useState("")

  useEffect(() => {
    setTime(Date.now().toString())
  }, [])

  return <div>{time}</div>
}

3. Использование random значений

Ошибка:

<div>{Math.random()}</div>

На сервере и клиенте значения разные.

4. Условный рендеринг через browser API

Проблема:

const isMobile = navigator.userAgent.includes("Mobile")

Лучше:

"use client"

import { useEffect, useState } from "react"

export default function MobileCheck() {
  const [isMobile, setIsMobile] = useState(false)

  useEffect(() => {
    setIsMobile(window.innerWidth < 768)
  }, [])

  return <div>{isMobile ? "Mobile" : "Desktop"}</div>
}

5. Компонент должен быть Client Component

В App Router Next.js серверные компоненты - default behavior.

Если используешь:

  • state

  • useEffect

  • browser API

нужен:

"use client"

6. Ошибки сторонних библиотек

Некоторые библиотеки:

  • charts

  • sliders

  • animation libs

не поддерживают SSR.

Решение через dynamic import

import dynamic from "next/dynamic"

const Chart = dynamic(() => import("./Chart"), {
  ssr: false,
})

Как быстро понять причину hydration error

Проверь:

  • есть ли window

  • используется ли Date.now()

  • есть ли Math.random()

  • есть ли browser API

  • совпадает ли HTML сервера и клиента

Лучший способ избежать hydration problems

Правило:

Всё, что зависит от браузера:

  • рендерить только на клиенте.

Полезный паттерн

"use client"

import { useEffect, useState } from "react"

export default function Component() {
  const [mounted, setMounted] = useState(false)

  useEffect(() => {
    setMounted(true)
  }, [])

  if (!mounted) return null

  return <div>Client Content</div>
}

Этот подход часто спасает сложные UI-компоненты.

Итог

Hydration failed в Next.js возникает, когда сервер и клиент рендерят разный HTML.

Самые частые причины:

  • window

  • document

  • Date.now()

  • Math.random()

  • browser API

  • SSR-несовместимые библиотеки

Главное правило:

сервер и клиент должны генерировать одинаковую разметку до hydration.

Комментарии

Пока нет комментариев. Будьте первым, кто напишет.

Чтобы оставить комментарий, войдите в аккаунт.

Похожие статьи