mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-26 01:33:02 +00:00
core(advanced-guides): 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
67c3c20db0
commit
6206a99c10
|
|
@ -181,7 +181,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/).
|
||||
|
||||
|
|
@ -190,76 +190,58 @@ The first client-side render output (in the browser) **must be exactly the same*
|
|||
Usage example:
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import React from // useState,
|
||||
// useEffect
|
||||
'react';
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||
|
||||
const isFetchingLocationMessage = 'fetching location...';
|
||||
|
||||
const MyComponent = () => {
|
||||
// highlight-start
|
||||
// Recommended
|
||||
const isBrowser = useIsBrowser();
|
||||
const location = isBrowser ? window.location.href : 'fetching location...';
|
||||
const location = isBrowser ? window.location.href : isFetchingLocationMessage;
|
||||
|
||||
// Not Recommended
|
||||
// using typeof window !== 'undefined' will still work in this example
|
||||
// but not recommended as it may cause issues depending on your business logic
|
||||
const isWindowDefined = typeof window !== 'undefined';
|
||||
const thisWillWorkButNotRecommended = isWindowDefined
|
||||
? window.location.href
|
||||
: isFetchingLocationMessage;
|
||||
|
||||
/*
|
||||
const [isFetchingLocation, setIsFetchingLocation] = useState(
|
||||
location === isFetchingLocationMessage
|
||||
)
|
||||
// Please note that `isFetchingLocation` initial value will be `true`
|
||||
// even though window is actually defined
|
||||
// because component has actually rendered once before hydration
|
||||
// subsequent renders will not update the useState
|
||||
// and may cause issues with business logic
|
||||
|
||||
// Do this instead
|
||||
const [isFetchingLocation, setIsFetchingLocation] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
setIsFetchingLocation(location === isFetchingLocationMessage)
|
||||
}, [isBrowser])
|
||||
*/
|
||||
|
||||
// highlight-end
|
||||
return <span>{location}</span>;
|
||||
return (
|
||||
<div>
|
||||
{/* Recommended */}
|
||||
{location}
|
||||
|
||||
{/* Not Recommended */}
|
||||
{thisWillWorkButNotRecommended}
|
||||
</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`
|
||||
|
||||
### `useEffect` {#useeffect}
|
||||
|
||||
Lastly, you can put your logic in `useEffect()` to delay its execution until after first CSR. This is most appropriate if you are only performing side-effects but don't _get_ data from the client state.
|
||||
|
|
|
|||
Loading…
Reference in New Issue