|
1 | 1 | 'use client' |
2 | 2 |
|
3 | | -import { useEffect, useRef } from 'react' |
| 3 | +import { useEffect } from 'react' |
4 | 4 | import { usePathname } from 'next/navigation' |
5 | 5 |
|
| 6 | +/** |
| 7 | + * Module-level flag so the popstate signal survives layout remounts when the |
| 8 | + * user navigates across sections (e.g., blog ↔ integrations ↔ models), where |
| 9 | + * the outgoing layout — and its component instances — unmount before the |
| 10 | + * incoming layout's effect runs. |
| 11 | + */ |
| 12 | +let isPopNavigation = false |
| 13 | + |
| 14 | +if (typeof window !== 'undefined') { |
| 15 | + window.addEventListener('popstate', () => { |
| 16 | + isPopNavigation = true |
| 17 | + }) |
| 18 | +} |
| 19 | + |
6 | 20 | /** |
7 | 21 | * Resets window scroll to the top on App Router pathname changes. |
8 | 22 | * |
9 | 23 | * Next.js's default scroll handling only brings the new Page element into view, |
10 | 24 | * which often resolves to "no scroll" inside shared layouts (see vercel/next.js#64435). |
11 | | - * Popstate-driven navigations are skipped so browser back/forward scroll restoration |
12 | | - * is preserved. |
| 25 | + * |
| 26 | + * Popstate-driven navigations are skipped so browser back/forward scroll |
| 27 | + * restoration is preserved, and hash-anchor navigations are skipped so the |
| 28 | + * browser's native anchor scroll wins. |
13 | 29 | */ |
14 | 30 | export function ScrollToTop() { |
15 | 31 | const pathname = usePathname() |
16 | | - const isPopNavigationRef = useRef(false) |
17 | | - |
18 | | - useEffect(() => { |
19 | | - const onPop = () => { |
20 | | - isPopNavigationRef.current = true |
21 | | - } |
22 | | - window.addEventListener('popstate', onPop) |
23 | | - return () => window.removeEventListener('popstate', onPop) |
24 | | - }, []) |
25 | 32 |
|
26 | 33 | useEffect(() => { |
27 | | - if (isPopNavigationRef.current) { |
28 | | - isPopNavigationRef.current = false |
| 34 | + if (isPopNavigation) { |
| 35 | + isPopNavigation = false |
29 | 36 | return |
30 | 37 | } |
| 38 | + if (window.location.hash) return |
31 | 39 | window.scrollTo(0, 0) |
32 | 40 | }, [pathname]) |
33 | 41 |
|
|
0 commit comments