Эта ошибка возникает, когда HTML, сгенерированный на сервере (SSR), не совпадает с HTML, который рендерится на клиенте. React ожидает, что серверный и клиентский HTML будут идентичны, чтобы успешно выполнить процесс «гидратации». Если они различаются, React сбрасывает серверный HTML и перерендеривает дерево на клиенте, что может повлиять на производительность.
Основные причины ошибки
- Использование
typeof window !== 'undefined'
или других клиентских проверок в SSR-компонентах.- Сервер не имеет доступа к объекту
window
, поэтому условные проверки, зависящие от клиента, могут привести к различиям в HTML.
- Сервер не имеет доступа к объекту
- Использование переменных, которые меняются при каждом рендере:
Date.now()
,Math.random()
или другие динамические значения, которые генерируют разные результаты на сервере и клиенте.
- Форматирование даты или локализация:
- Если сервер и клиент используют разные локали, это может привести к различиям в форматировании текста.
- Динамические данные без передачи их снимка (snapshot):
- Если данные, используемые для рендеринга, изменяются между сервером и клиентом, это вызовет несоответствие.
- Неправильная вложенность HTML-тегов:
- Например, использование некорректной структуры HTML, такой как
<div><p></div></p>
.
- Например, использование некорректной структуры HTML, такой как
- Браузерные расширения:
- Некоторые расширения могут изменять HTML до того, как React загрузится, что вызовет ошибку.
Как исправить ошибку
1. Проверка на typeof window
Если вы используете условие if (typeof window !== 'undefined')
, убедитесь, что оно применяется только в клиентских компонентах. Например:
javascript
"use client";
import { useEffect, useState } from "react";
export default function Example() {
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
return (
<div>
{isClient ? <p>Это клиент</p> : <p>Загрузка...</p>}
</div>
);
}
2. Избегайте использования Date.now()
и Math.random()
Если вам нужно использовать динамические значения, убедитесь, что они одинаковы на сервере и клиенте. Например:
javascript
const randomValue = useMemo(() => 42, []); // Используйте фиксированное значение
Или передавайте данные через props
:
javascript
export async function getServerSideProps() {
return {
props: {
timestamp: Date.now(),
},
};
}
export default function Page({ timestamp }) {
return <p>Время: {timestamp}</p>;
}
3. Используйте одинаковую локаль
Если вы форматируете даты или числа, убедитесь, что сервер и клиент используют одну и ту же локаль. Например:
javascript
import { useEffect, useState } from "react";
export default function Page() {
const [formattedDate, setFormattedDate] = useState("");
useEffect(() => {
const date = new Date();
setFormattedDate(date.toLocaleDateString("ru-RU"));
}, []);
return <p>Дата: {formattedDate || "Загрузка..."}</p>;
}
4. Передавайте данные через props
Если вы используете данные из API, убедитесь, что они передаются как props
на сервере:
javascript
export async function getServerSideProps() {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
return {
props: {
data,
},
};
}
export default function Page({ data }) {
return (
<div>
{data.map((item) => (
<p key={item.id}>{item.name}</p>
))}
</div>
);
}
5. Проверка HTML-структуры
Убедитесь, что HTML-теги правильно вложены. Например:Неправильно:
html
<div>
<p></div></p>
Правильно:
html
<div>
<p></p>
</div>
6. Отключение SSR для компонента
Если компонент должен рендериться только на клиенте, используйте директиву "use client"
:
javascript
"use client";
export default function ClientOnlyComponent() {
return <p>Этот компонент рендерится только на клиенте</p>;
}
Дополнительные советы
- Проверяйте консоль браузера: Часто React указывает, какой компонент вызвал ошибку.
- Отключите расширения браузера: Попробуйте открыть сайт в режиме инкогнито, чтобы исключить влияние расширений.
- Используйте
React.StrictMode
: Это поможет выявить потенциальные проблемы в вашем коде.
Если ошибка сохраняется, напишите, и я помогу вам разобраться! 😊