Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disable hydration / only partially hydrate a Next.js app

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

  • React?
  • Next.js?

Thanks

like image 574
Lukas Avatar asked Mar 28 '19 08:03

Lukas


People also ask

What is hydration error in next JS?

When css-in-js libraries are not set up for pre-rendering (SSR/SSG) it will often lead to a hydration mismatch. In general this means the application has to follow the Next. js example for the library. For example if pages/_document is missing and the Babel plugin is not added.

What is hydration mismatch?

A hydration mismatch is when the content rendered to HTML in Node. js is not the same than the content rendered in the browser. Hydration mismatches can induce performance degradation and bugs and should therefore be avoided.

How do I use getInitialProps in next JS?

getInitialProps is used to asynchronously fetch some data, which then populates props . Data returned from getInitialProps is serialized when server rendering, similar to what JSON.stringify does. Make sure the returned object from getInitialProps is a plain Object and not using Date , Map or Set .


1 Answers

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: '' },
  })
}
``
like image 152
Aral Roca Avatar answered Sep 18 '22 23:09

Aral Roca