Search code examples
reactjsnext.jszustand

nextjs ssr cause client side state persist conflict


I use zustand to manage my states.

I persist the width state in user local storage then reload and in console, I see an error like this :

Prop style did not match. Server: "width:400px" Client: "width:385px"

It's because the default state is 400, but it is 385 in client local storage and when it loads it makes conflict

it gets worst when i try to persist a state that mount & unmount a component because default server state is mount but client state is unmount and it makes client crash


Solution

  • In my case, this answer helps.

    https://github.com/vercel/next.js/issues/7417#issuecomment-660241345

    When React do the rehydration phase, if the output rendered in the server side is different from the generated in the rehydration phase this makes React be confused and makes him render the output in a wrong way, so what you need to do is assure that the output generated by the server be exactly the same to the generated by the rehydration phase (that have access to browser apis, this is the reason why the output differs) and wait for the component to mount, that happens after the rehydration phase to make any changes based in-browser API or any other type of client-side data

    Your case

    Mind that initial state must be always same between server side and client side, and you can safely change the client side state (and react tree) after the component is mounted.

    import { useState, useEffect } from "react";
    
    // default width for SSR
    const defaultWidth = 400;
    
    const useWidth = () => {
      const [width, setWidth] = useState(defaultWidth);
      // onMounted
      useEffect(() => {
        if (typeof window === "undefined") return;
        setWidth(window.innerWidth);
      }, []);
    
      return width;
    };