mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-22 19:17:46 +02:00
docs(core): removing the newly added explanations for useIsBrowser
as they are not in the scope of only Docusaurus but all the React SSR frameworks and extending the existing example to include a bit more context
This commit is contained in:
parent
47cc3e62e8
commit
67c3c20db0
1 changed files with 17 additions and 60 deletions
|
@ -413,7 +413,7 @@ Returns `true` when the React app has successfully hydrated in the browser.
|
||||||
|
|
||||||
:::caution
|
:::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/).
|
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 = () => {
|
const MyComponent = () => {
|
||||||
// highlight-start
|
// highlight-start
|
||||||
|
// Recommended
|
||||||
const isBrowser = useIsBrowser();
|
const isBrowser = useIsBrowser();
|
||||||
|
|
||||||
|
// Not Recommended
|
||||||
|
// using typeof window !== 'undefined' will lead to mismatching render output
|
||||||
|
const isWindowDefined = typeof window !== 'undefined';
|
||||||
// highlight-end
|
// highlight-end
|
||||||
return <div>{isBrowser ? 'Client' : 'Server'}</div>;
|
return (
|
||||||
|
<div>
|
||||||
|
{/* Recommended */}
|
||||||
|
{isBrowser ? 'Client (hydration completed)' : 'Server'}
|
||||||
|
|
||||||
|
{/* Not Recommended */}
|
||||||
|
{isWindowDefined
|
||||||
|
? 'Client (hydration NOT completed, will mismatch)'
|
||||||
|
: 'Server'}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 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 <span>{someParam}</span>;
|
|
||||||
// highlight-end
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
Adding `useIsBrowser()` checks to derived values will have no effect. Wrapping the `<span>` with `<BrowserOnly>` 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 <span>{someParam}</span>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// highlight-start
|
|
||||||
const MyComponentParent = () => {
|
|
||||||
const isBrowser = useIsBrowser();
|
|
||||||
|
|
||||||
if (!isBrowser) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <MyComponent />;
|
|
||||||
};
|
|
||||||
// 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 `<MyComponent />` 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}
|
### `useBaseUrl` {#useBaseUrl}
|
||||||
|
|
||||||
React hook to prepend your site `baseUrl` to a string.
|
React hook to prepend your site `baseUrl` to a string.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue