Reputation: 10340
Is it possible to enforce an SSR-only mode in Next.js and only partially hydrate the page? Let's say I have this app:
components/dynamic.jsx
export default () => (
<button onClick={() => console.log("I have been clicked")}>Click me</button>
)
pages/index.jsx
import DynamicComponent from "../components/dynamic.jsx";
export default () => (
<div>
<h1>Hello World</h1>
<p>Lorem ipsum</p>
<Hydrate>
<DynamicComponent />
</Hydrate>
</div>
);
Now assume we are rendering pages/index.jsx
with Next.js
so it will be rendered on the server and fully hydrated on the client. For performance reasons (shrink bundle size, reduce execution time) and to have the app play nicer with ads (😒) I only want to hydrate the DynamicComponent
on the client and at best only load the JavaScript for the DynamicComponent
to the client.
Ist that possible with
Thanks
Upvotes: 22
Views: 29915
Reputation: 5889
You can do it with a hack:
<>
<StaticContent>
<h1>Hello World</h1>
<p>Lorem ipsum</p>
</StaticContent>
<DynamicComponent />
</>
And the StaticContent
component:
import { createElement, useRef, useState, useEffect } from 'react'
function useStaticContent() {
const ref = useRef(null)
const [render, setRender] = useState(typeof window === 'undefined')
useEffect(() => {
// check if the innerHTML is empty as client side navigation
// need to render the component without server-side backup
const isEmpty = ref.current.innerHTML === ''
if (isEmpty) {
setRender(true)
}
}, [])
return [render, ref]
}
export default function StaticContent({ children, element = 'div', ...props }) {
const [render, ref] = useStaticContent()
// if we're in the server or a spa navigation, just render it
if (render) {
return createElement(element, {
...props,
children,
})
}
// avoid re-render on the client
return createElement(element, {
...props,
ref,
suppressHydrationWarning: true,
dangerouslySetInnerHTML: { __html: '' },
})
}
It loads the javascript anyway, but does not re-execute it, i.e. it does not do the hydration of these components.
Update: If you use Next.js it is better to use the App folder that already supports partial hydration with the server components and client components.
Upvotes: 22
Reputation: 9
For this error you can simply use this trick : I'm changing css class from module file and then taking the Hydration error. In fact you will render the component in react side same as user intraction.
import cl from "./ButtonIno.module.scss";
import {useEffect, useState} from "react";
const ButtonIno = ({children,type}) => {
const [show,setShow] = useState(false);
let styles = {}
useEffect(()=>{
setShow(true);
},[]);
return (
<>
{show &&
<div className={cl[type]}>
{/*<div>*/}
<a href="" >
{children}
</a>
</div>
}
</>
);
};
export default ButtonIno;
Upvotes: 0