Коротко — проблема в том, что при SPA-навигации layout остаётся, DOM блоков AdSense не перерисовывается, а сам скрипт Google не «видит» смену страницы и не запрашивает новый баннер. Решение — 1) загрузить скрипт adsbygoogle один раз (в корневом layout) и 2) при смене параметра маршрута в клиентском компоненте заново инициализировать слот (либо форсировать его размонт/монт). Ниже — проверенный и безопасный шаблон.
1) Загрузите скрипт один раз (root layout, server или client — важно не дублировать):
- в app/layout.tsx (или другом верхнем layout) добавьте:
```
import Script from 'next/script'
export default function RootLayout({ children }) {
return (
<html>
<head>
<Script
id="adsense"
strategy="afterInteractive"
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"
data-ad-client="ca-pub-XXXXXXXXXXXX"
crossOrigin="anonymous"
/>
</head>
<body>{children}</body>
</html>
)
}
```
(укажите ваш ca-pub id)
2) Создайте клиентский компонент для слота рекламы, который будет реагировать на изменение пути/параметра. Важные моменты: "use client", usePathname из next/navigation, ключ (key) на <ins> по pathname или параметру и вызов (window.adsbygoogle = window.adsbygoogle || []).push({}) в useEffect.
Пример компонента:
```
'use client'
import { useEffect } from 'react'
import { usePathname } from 'next/navigation'
declare global {
interface Window { adsbygoogle?: any[] }
}
export default function AdSlot({ adSlot, style = { display: 'block' } }) {
const pathname = usePathname()
useEffect(() => {
// Попробуем инициализировать слот; если скрипт ещё не загрузился — вызов не упадёт
try {
(window.adsbygoogle = window.adsbygoogle || []).push({})
} catch (err) {
console.warn('Adsense push failed', err)
}
}, [pathname]) // срабатывает при смене пути / динамического параметра
return (
<ins
className="adsbygoogle"
style={style}
data-ad-client="ca-pub-XXXXXXXXXXXX"
data-ad-slot={adSlot}
data-ad-format="auto"
key={pathname} // форсируем размонт/монт при смене пути
/>
)
}
```
Почему это работает:
- Script загружен единожды (не дублируйте его в вложенных layout).
- Установка ключа key={pathname} заставляет React размонтировать старый <ins> и смонтировать новый DOM-элемент — это необходимо, чтобы AdSense «увидел» новый контейнер.
- (window.adsbygoogle).push({}) сообщает библиотеке, что нужно обработать новый <ins> и подгрузить объявление.
Дополнительные советы и подводные камни:
- Не загружайте adsbygoogle.js в каждом вложенном layout — будет дублирование и ошибки.
- Убедитесь, что компонент помечен как client ("use client"), иначе usePathname не сработает.
- Иногда полезно ждать, пока скрипт загрузится, прежде чем push вызывать; в большинстве случаев push в useEffect после рендера сработает корректно. Если наблюдаете race condition, можно реализовать ожидание window.adsbygoogle с таймаутом.
- Соблюдайте правила AdSense: обновлять объявления на каждой «виртуальной» навигации можно, но не обновляйте их слишком часто (не выполнять авто-рефреш на таймере и т.п.).
Если хотите, могу прислать интеграцию с конкретной структурой вашего layout (покажите фрагменты), или добавить ожидание загрузки скрипта перед push.