Skip to content

Commit

Permalink
fix(theme): fix useWindowSize React hydration issue (#9446)
Browse files Browse the repository at this point in the history
  • Loading branch information
slorber authored Oct 25, 2023
1 parent d07567e commit 8d19054
Showing 1 changed file with 10 additions and 16 deletions.
26 changes: 10 additions & 16 deletions packages/docusaurus-theme-common/src/hooks/useWindowSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ const DesktopThresholdWidth = 996;

function getWindowSize() {
if (!ExecutionEnvironment.canUseDOM) {
return windowSizes.ssr;
throw new Error(
'getWindowSize() should only be called after React hydration',
);
}
return window.innerWidth > DesktopThresholdWidth
? windowSizes.desktop
: windowSizes.mobile;
}

const DevSimulateSSR = process.env.NODE_ENV === 'development' && true;

/**
* Gets the current window size as an enum value. We don't want it to return the
* actual width value, so that it only re-renders once a breakpoint is crossed.
Expand All @@ -39,32 +39,26 @@ const DevSimulateSSR = process.env.NODE_ENV === 'development' && true;
* may need to render BOTH the mobile/desktop elements (and hide one of them
* with mediaquery). We don't return `undefined` on purpose, to make it more
* explicit.
*
* In development mode, this hook will still return `"ssr"` for one second, to
* catch potential layout shifts, similar to strict mode calling effects twice.
*/
export function useWindowSize(): WindowSize {
const [windowSize, setWindowSize] = useState<WindowSize>(() => {
if (DevSimulateSSR) {
return 'ssr';
}
return getWindowSize();
});
const [windowSize, setWindowSize] = useState<WindowSize>(
() =>
// super important to return a constant value to avoid hydration mismatch
// see https://github.com/facebook/docusaurus/issues/9379
'ssr',
);

useEffect(() => {
function updateWindowSize() {
setWindowSize(getWindowSize());
}

const timeout = DevSimulateSSR
? window.setTimeout(updateWindowSize, 1000)
: undefined;
updateWindowSize();

window.addEventListener('resize', updateWindowSize);

return () => {
window.removeEventListener('resize', updateWindowSize);
clearTimeout(timeout);
};
}, []);

Expand Down

0 comments on commit 8d19054

Please sign in to comment.