diff --git a/website/docs/docusaurus-core.mdx b/website/docs/docusaurus-core.mdx
index 251f7d0fc3..f7847cace2 100644
--- a/website/docs/docusaurus-core.mdx
+++ b/website/docs/docusaurus-core.mdx
@@ -413,7 +413,7 @@ Returns `true` when the React app has successfully hydrated in the browser.
:::caution
-Use this hook instead of `typeof windows !== 'undefined'` in React rendering logic.
+Use this hook instead of `typeof windows !== 'undefined'` in React rendering logic because `window` may be defined but hydration may not necessarily have been completed yet.
The first client-side render output (in the browser) **must be exactly the same** as the server-side render output (Node.js). Not following this rule can lead to unexpected hydration behaviors, as described in [The Perils of Rehydration](https://www.joshwcomeau.com/react/the-perils-of-rehydration/).
@@ -427,70 +427,27 @@ import useIsBrowser from '@docusaurus/useIsBrowser';
const MyComponent = () => {
// highlight-start
+ // Recommended
const isBrowser = useIsBrowser();
+
+ // Not Recommended
+ // using typeof window !== 'undefined' will lead to mismatching render output
+ const isWindowDefined = typeof window !== 'undefined';
// highlight-end
- return
{isBrowser ? 'Client' : 'Server'}
;
+ return (
+
+ {/* Recommended */}
+ {isBrowser ? 'Client (hydration completed)' : 'Server'}
+
+ {/* Not Recommended */}
+ {isWindowDefined
+ ? 'Client (hydration NOT completed, will mismatch)'
+ : 'Server'}
+
+ );
};
```
-#### A caveat to know when using `useIsBrowser`
-
-Because it does not do `typeof windows !== 'undefined'` check but rather checks if the React app has successfully hydrated, the following code will not work as intended:
-
-```jsx
-import React from 'react';
-import useIsBrowser from '@docusaurus/useIsBrowser';
-
-const MyComponent = () => {
- // highlight-start
- const isBrowser = useIsBrowser();
- const url = isBrowser ? new URL(window.location.href) : undefined;
- const someQueryParam = url?.searchParams.get('someParam');
- const [someParam, setSomeParam] = useState(someQueryParam || 'fallbackValue');
-
- // renders fallbackValue instead of the value of someParam query parameter
- // because the component has already rendered but hydration has not completed
- // useState references the fallbackValue
- return {someParam};
- // highlight-end
-};
-```
-
-Adding `useIsBrowser()` checks to derived values will have no effect. Wrapping the `` with `` will also have no effect. To have `useState` reference the correct value, which is the value of the `someParam` query parameter, `MyComponent`'s first render should actually happen after `useIsBrowser` returns true. Because you cannot have if statements inside the component before any hooks, you need to resort to doing `useIsBrowser()` in the parent component as such:
-
-```jsx
-import React, {useState} from 'react';
-import useIsBrowser from '@docusaurus/useIsBrowser';
-
-const MyComponent = () => {
- const isBrowser = useIsBrowser();
- const url = isBrowser ? new URL(window.location.href) : undefined;
- const someQueryParam = url?.searchParams.get('someParam');
- const [someParam, setSomeParam] = useState(someQueryParam || 'fallbackValue');
-
- return {someParam};
-};
-
-// highlight-start
-const MyComponentParent = () => {
- const isBrowser = useIsBrowser();
-
- if (!isBrowser) {
- return null;
- }
-
- return ;
-};
-// highlight-end
-
-export default MyComponentParent;
-```
-
-There are a couple more alternative solutions to this problem. However all of them require adding checks in **the parent component**:
-
-1. You can wrap `` with [`BrowserOnly`](./docusaurus-core.mdx#browseronly)
-2. You can use `canUseDOM` from [`ExecutionEnvironment`](./docusaurus-core.mdx#executionenvironment) and `return null` when `canUseDOM` is `false`
-
### `useBaseUrl` {#useBaseUrl}
React hook to prepend your site `baseUrl` to a string.