This blog was last modified 543 days before.

Next.js is using Server Side Generate (SSG) and Server Side Rendering (SSR).

Next.js Server Side pre-rendering

We already know that we can use use client to mark a component/route to be client side. But based on Next.js Offical Docs, if we are rendering Full Page Load and not Subsequent Navigation, then Next.js will still do some pre-rendering work.

This feature may cause a Next.js Hydration Error in some cases, for example, when working with zustand persist.

Why Error Occured

Next.js has a hydration when rendering full page load. Zustand has rehydration when using persist middleware.

When loading a full page in browser, persist will try to execute rehydration with data in local storage, which lead to HTML and DOM change.

If persist rehydration finished before Next.js hydration, then Next.js will found that the HTML now (which is changed by persist rehydration operation) is not the same as one pre-rendered on server, so Next.js will throw an error complaining hydration failed.

How to solve

Zustand was also awared of this problem, and gave their solution in Zustand Offical Doc

Basically, we need a new function call useStore() as a React Hook.

// useStore.ts
import { useState, useEffect } from 'react'

const useStore = <T, F>(
  store: (callback: (state: T) => unknown) => unknown,
  callback: (state: T) => F
) => {
  const result = store(callback) as F
  const [data, setData] = useState<F>()

  useEffect(() => {
    setData(result)
  }, [result])

  return data
}

export default useStore

Using this hook could make sure that the rehydration work of Zustand happened after Next.js hydration, which finally prevent Next.js Hydration Error.

No any code need to be changed of your store, you only need

  • useStore() function
  • A slightly different method of using store in your component

You can use useStore() in your React components like below:

// yourComponent.tsx

import useStore from './useStore'
import { useBearStore } from './stores/useBearStore'

const bears = useStore(useBearStore, (state) => state.bears)