Created
June 5, 2022 14:54
-
-
Save esamattis/99a3d95e6445f5ecb360683867710acd to your computer and use it in GitHub Desktop.
Prevent React hydration on specific element (HACK)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Render a div which preserves its server-side content on browser hydration. | |
*/ | |
function NoHydrate(props: { id?: string; children: React.ReactNode }) { | |
const id = props.id ?? "no-hydrate"; | |
const container = useRef<HTMLDivElement>(null); | |
const save = useRef<Node[]>(); | |
// During the first render capture clones of the children. Reading the DOM | |
// during React render is a hack but the only way to access the DOM before | |
// React destroys it. | |
if (typeof window !== "undefined" && !save.current) { | |
const style = document.getElementById(id); | |
if (style && !save.current) { | |
save.current = Array.from(style.childNodes).map((child) => | |
child.cloneNode(true), | |
); | |
} | |
} | |
// After the React render React has potentially destoyed the children so we | |
// restore them | |
useLayoutEffect(() => { | |
if (save.current) { | |
for (const node of save.current) { | |
container.current?.appendChild(node); | |
} | |
} | |
}, []); | |
return useMemo( | |
() => ( | |
<div id={id} ref={container} suppressHydrationWarning> | |
{props.children} | |
</div> | |
), | |
[id], | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment