fix(theme): make `useHistorySelector()` hydration-safe + use it read search/hash in theme (#11263)
Some checks failed
Argos CI / take-screenshots (push) Has been cancelled
Build Hash Router / Build Hash Router (push) Has been cancelled
Canary Release / Publish Canary (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Continuous Releases / Continuous Releases (push) Has been cancelled
E2E Tests / E2E — Yarn v1 (18.0) (push) Has been cancelled
E2E Tests / E2E — Yarn v1 (20) (push) Has been cancelled
E2E Tests / E2E — Yarn v1 (22) (push) Has been cancelled
E2E Tests / E2E — Yarn v1 (24) (push) Has been cancelled
E2E Tests / E2E — Yarn v1 Windows (push) Has been cancelled
E2E Tests / E2E — Yarn Berry (node-modules, -s) (push) Has been cancelled
E2E Tests / E2E — Yarn Berry (node-modules, -st) (push) Has been cancelled
E2E Tests / E2E — Yarn Berry (pnp, -s) (push) Has been cancelled
E2E Tests / E2E — Yarn Berry (pnp, -st) (push) Has been cancelled
E2E Tests / E2E — npm (push) Has been cancelled
E2E Tests / E2E — pnpm (push) Has been cancelled

This commit is contained in:
Sébastien Lorber 2025-06-13 18:49:28 +02:00 committed by GitHub
parent a392c33b8e
commit 6cb955987e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 18 additions and 10 deletions

View File

@ -134,11 +134,6 @@ function throwOnConsole(page: Page) {
// it's already happening in main branch
'Failed to load resource: the server responded with a status of 404 (Not Found)',
// TODO legit hydration bugs to fix on embeds of /docs/styling-layout
// useLocation() returns window.search/hash immediately :s
'/docs/configuration?docusaurus-theme=light',
'/docs/configuration?docusaurus-theme=dark',
// Warning because react-live not supporting React automatic JSX runtime
// See https://github.com/FormidableLabs/react-live/issues/405
'Your app (or one of its dependencies) is using an outdated JSX transform. Update to the modern JSX transform for faster performance',

View File

@ -13,7 +13,7 @@ import {
useDocsPreferredVersion,
} from '@docusaurus/plugin-content-docs/client';
import {translate} from '@docusaurus/Translate';
import {useLocation} from '@docusaurus/router';
import {useHistorySelector} from '@docusaurus/theme-common';
import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
import type {
@ -119,7 +119,8 @@ export default function DocsVersionDropdownNavbarItem({
versions: configs,
...props
}: Props): ReactNode {
const {search, hash} = useLocation();
const search = useHistorySelector((history) => history.location.search);
const hash = useHistorySelector((history) => history.location.hash);
const activeDocContext = useActiveDocContext(docsPluginId);
const {savePreferredVersionName} = useDocsPreferredVersion(docsPluginId);
const versionItems = useVersionItems({docsPluginId, configs});

View File

@ -9,7 +9,7 @@ import React, {type ReactNode} from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import {useAlternatePageUtils} from '@docusaurus/theme-common/internal';
import {translate} from '@docusaurus/Translate';
import {useLocation} from '@docusaurus/router';
import {useHistorySelector} from '@docusaurus/theme-common';
import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
import IconLanguage from '@theme/Icon/Language';
import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem';
@ -28,7 +28,8 @@ export default function LocaleDropdownNavbarItem({
i18n: {currentLocale, locales, localeConfigs},
} = useDocusaurusContext();
const alternatePageUtils = useAlternatePageUtils();
const {search, hash} = useLocation();
const search = useHistorySelector((history) => history.location.search);
const hash = useHistorySelector((history) => history.location.hash);
const localeItems = locales.map((locale): LinkLikeNavbarItemProps => {
const baseTo = `pathname://${alternatePageUtils.createUrl({

View File

@ -57,7 +57,18 @@ export function useHistorySelector<Value>(
return useSyncExternalStore(
history.listen,
() => selector(history),
() => selector(history),
() =>
selector({
...history,
location: {
...history.location,
// On the server/hydration, these attributes should always be empty
// Forcing empty state makes this hook safe from hydration errors
search: '',
hash: '',
state: undefined,
},
}),
);
}