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 // it's already happening in main branch
'Failed to load resource: the server responded with a status of 404 (Not Found)', '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 // Warning because react-live not supporting React automatic JSX runtime
// See https://github.com/FormidableLabs/react-live/issues/405 // 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', '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, useDocsPreferredVersion,
} from '@docusaurus/plugin-content-docs/client'; } from '@docusaurus/plugin-content-docs/client';
import {translate} from '@docusaurus/Translate'; import {translate} from '@docusaurus/Translate';
import {useLocation} from '@docusaurus/router'; import {useHistorySelector} from '@docusaurus/theme-common';
import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem'; import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem'; import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
import type { import type {
@ -119,7 +119,8 @@ export default function DocsVersionDropdownNavbarItem({
versions: configs, versions: configs,
...props ...props
}: Props): ReactNode { }: 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 activeDocContext = useActiveDocContext(docsPluginId);
const {savePreferredVersionName} = useDocsPreferredVersion(docsPluginId); const {savePreferredVersionName} = useDocsPreferredVersion(docsPluginId);
const versionItems = useVersionItems({docsPluginId, configs}); const versionItems = useVersionItems({docsPluginId, configs});

View File

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

View File

@ -57,7 +57,18 @@ export function useHistorySelector<Value>(
return useSyncExternalStore( return useSyncExternalStore(
history.listen, history.listen,
() => selector(history), () => 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,
},
}),
); );
} }