diff --git a/docs/start/framework/react/guide/execution-model.md b/docs/start/framework/react/guide/execution-model.md index 03556345e93..ab78c6fed5f 100644 --- a/docs/start/framework/react/guide/execution-model.md +++ b/docs/start/framework/react/guide/execution-model.md @@ -98,6 +98,31 @@ function Analytics() { } ``` +#### useHydrated Hook + +For more granular control over hydration-dependent behavior, use the `useHydrated` hook. It returns a boolean indicating whether the client has been hydrated: + +```tsx +import { useHydrated } from '@tanstack/react-router' + +function TimeZoneDisplay() { + const hydrated = useHydrated() + const timeZone = hydrated + ? Intl.DateTimeFormat().resolvedOptions().timeZone + : 'UTC' + + return
Your timezone: {timeZone}
+} +``` + +**Behavior:** + +- **During SSR**: Always returns `false` +- **First client render**: Returns `false` +- **After hydration**: Returns `true` (and stays `true` for all subsequent renders) + +This is useful when you need to conditionally render content based on client-side data (like browser timezone, locale, or localStorage) while providing a sensible fallback for server rendering. + ### Environment-Specific Implementations ```tsx diff --git a/docs/start/framework/solid/guide/execution-model.md b/docs/start/framework/solid/guide/execution-model.md index 98d9c2b7cad..c2cedb167a2 100644 --- a/docs/start/framework/solid/guide/execution-model.md +++ b/docs/start/framework/solid/guide/execution-model.md @@ -98,6 +98,30 @@ function Analytics() { } ``` +#### useHydrated Hook + +For more granular control over hydration-dependent behavior, use the `useHydrated` hook. It returns an accessor (signal) indicating whether the client has been hydrated: + +```tsx +import { useHydrated } from '@tanstack/solid-router' + +function TimeZoneDisplay() { + const hydrated = useHydrated() + const timeZone = () => + hydrated() ? Intl.DateTimeFormat().resolvedOptions().timeZone : 'UTC' + + return
Your timezone: {timeZone()}
+} +``` + +**Behavior:** + +- **During SSR**: Always returns `false` +- **First client render**: Returns `false` +- **After hydration**: Returns `true` (and stays `true` for all subsequent renders) + +This is useful when you need to conditionally render content based on client-side data (like browser timezone, locale, or localStorage) while providing a sensible fallback for server rendering. + ### Environment-Specific Implementations ```tsx diff --git a/packages/react-router/src/ClientOnly.tsx b/packages/react-router/src/ClientOnly.tsx index 7269b92e0ce..be16ff2eee1 100644 --- a/packages/react-router/src/ClientOnly.tsx +++ b/packages/react-router/src/ClientOnly.tsx @@ -63,7 +63,7 @@ export function ClientOnly({ children, fallback = null }: ClientOnlyProps) { /** * Return a boolean indicating whether client hydration has occurred. */ -function useHydrated(): boolean { +export function useHydrated(): boolean { return React.useSyncExternalStore( subscribe, () => true, diff --git a/packages/react-router/src/index.tsx b/packages/react-router/src/index.tsx index 77270748939..29d293fe986 100644 --- a/packages/react-router/src/index.tsx +++ b/packages/react-router/src/index.tsx @@ -130,7 +130,7 @@ export { useAwaited, Await } from './awaited' export type { AwaitOptions } from './awaited' export { CatchBoundary, ErrorComponent } from './CatchBoundary' -export { ClientOnly } from './ClientOnly' +export { ClientOnly, useHydrated } from './ClientOnly' export { FileRoute, diff --git a/packages/solid-router/src/ClientOnly.tsx b/packages/solid-router/src/ClientOnly.tsx index e3e251a8489..6ed10d267b3 100644 --- a/packages/solid-router/src/ClientOnly.tsx +++ b/packages/solid-router/src/ClientOnly.tsx @@ -56,7 +56,7 @@ export function ClientOnly(props: ClientOnlyProps) { * ``` * @returns True if the JS has been hydrated already, false otherwise. */ -function useHydrated(): Solid.Accessor { +export function useHydrated(): Solid.Accessor { const [hydrated, setHydrated] = Solid.createSignal(false) Solid.onMount(() => { setHydrated(true) diff --git a/packages/solid-router/src/index.tsx b/packages/solid-router/src/index.tsx index 070216b839e..f3e4b635bef 100644 --- a/packages/solid-router/src/index.tsx +++ b/packages/solid-router/src/index.tsx @@ -211,7 +211,7 @@ export { useAwaited, Await } from './awaited' export type { AwaitOptions } from './awaited' export { CatchBoundary, ErrorComponent } from './CatchBoundary' -export { ClientOnly } from './ClientOnly' +export { ClientOnly, useHydrated } from './ClientOnly' export { FileRoute,