From 3e548e41863efa569bea8ed2d4e11dfa928bdbaf Mon Sep 17 00:00:00 2001 From: conico974 Date: Thu, 30 Oct 2025 14:33:26 +0100 Subject: [PATCH] Initialize hash on mount and improve navigation handling (#3774) --- packages/gitbook/src/components/hooks/useHash.tsx | 7 +++++-- packages/gitbook/src/components/hooks/useScrollPage.ts | 6 ++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/gitbook/src/components/hooks/useHash.tsx b/packages/gitbook/src/components/hooks/useHash.tsx index aff0358e6..fecbb9d7e 100644 --- a/packages/gitbook/src/components/hooks/useHash.tsx +++ b/packages/gitbook/src/components/hooks/useHash.tsx @@ -51,6 +51,8 @@ export const NavigationStatusProvider: React.FC = ({ ch // Cleanup timeout on unmount React.useEffect(() => { + // Initialize hash on mount - It could be null on SSR rehydration + setHash(getHash()); return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); @@ -73,7 +75,8 @@ export const NavigationStatusProvider: React.FC = ({ ch if (timeoutRef.current) { clearTimeout(timeoutRef.current); } - if (pathnameRef.current !== url.pathname) { + // We don't want to set isNavigating for same page hash navigation + if (pathnameRef.current !== url.pathname && !href.startsWith('#')) { timeoutRef.current = window.setTimeout(() => { setIsNavigating(true); timeoutRef.current = null; @@ -94,7 +97,7 @@ export const NavigationStatusProvider: React.FC = ({ ch }; /** - * Hook to get the current hash from the URL. + * Hook to get the current hash from the URL. The hash is set on navigation clicks **NOT** on hashchange events or on navigation end. * @see https://github.com/vercel/next.js/discussions/49465 * We use a different hack than this one, because for same page link it don't work * We can't use the `hashChange` event because it doesn't fire for `replaceState` and `pushState` which are used by Next.js. diff --git a/packages/gitbook/src/components/hooks/useScrollPage.ts b/packages/gitbook/src/components/hooks/useScrollPage.ts index d56619502..a63159fb5 100644 --- a/packages/gitbook/src/components/hooks/useScrollPage.ts +++ b/packages/gitbook/src/components/hooks/useScrollPage.ts @@ -1,6 +1,5 @@ 'use client'; -import { usePathname } from 'next/navigation'; import React from 'react'; import { useHash } from './useHash'; @@ -13,8 +12,7 @@ import { usePrevious } from './usePrevious'; export function useScrollPage() { const hash = useHash(); const previousHash = usePrevious(hash); - const pathname = usePathname(); - // biome-ignore lint/correctness/useExhaustiveDependencies: pathname should trigger it. + React.useEffect(() => { if (hash) { if (previousHash !== undefined && previousHash !== hash) { @@ -30,5 +28,5 @@ export function useScrollPage() { } window.scrollTo(0, 0); - }, [hash, previousHash, pathname]); + }, [hash, previousHash]); }