'Warning: Text content did not match. Server: "I'm out" Client: "I'm in" div

I'm using universal-cookie in Next.js project and this the simple code that return a warning in console:

import React, { useState } from "react";
import Cookies from "universal-cookie";
import styles from "../styles/Home.module.css";

export default function Home() {
  const cook = new Cookies();
  const [session, setSession] = useState(cook.get("key"));
  const setCookie = () => {
    cook.set("key", "hola", { secure: true });
    setSession(cook.get("key"));
  };
  const deleteCookie = () => {
    cook.remove("key", { secure: true });
    setSession(undefined);
  };

  return (
    <div className={styles.container}>
      <button onClick={() => setCookie()}>Save Cookie</button>
      <button onClick={() => deleteCookie()}>Delete Cookie</button>
      {session ? <>I'm in</> : <>I'm out</>}
    </div>
  );
}

When "I'M IN" and then I refresh the page the follow warning appear in console:

enter image description here

I have already looked everywhere for a solution.



Solution 1:[1]

Next.js pre-renders every page on the server.

This means that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript.

(...) When a page is loaded by the browser, its JavaScript code runs and makes the page fully interactive. (This process is called hydration.)

The HTML rendered on the browser doesn't match the one generated on the server because cook.get("key") returns different things in both.

There are a couple of options to solve the issue.


#1 Moving setting state to useEffect

The first solution is to move setting the state inside a useEffect.

export default function Home() {
    const cook = new Cookies();
    const [session, setSession] = useState();
    
    // `setCookie` and `deleteCookie` code here

    useEffect(() => {
        setSession(cook.get("key"));
    }, []);

    return (
        <div className={styles.container}>
            <button onClick={() => setCookie()}>Save Cookie</button>
            <button onClick={() => deleteCookie()}>Delete Cookie</button>
            {session ? <>I'm in</> : <>I'm out</>}
        </div>
    );
}

#2 Using next/dynamic with { ssr: false }

As an alternate solution, the issue can also be circumvented by dynamically importing the React component with next/dynamic using { ssr: false }, wherever the component is used. This prevents the component from being included on the server, and dynamically loads it on the client-side only.

const Home = dynamic(
    () => import('../components/Home'),
    { ssr: false }
)

Solution 2:[2]

using suppresshydrationwarning attribute on the html element (which differs) worked for me.. It acts only at single level as per documentation below:

https://reactjs.org/docs/dom-elements.html#suppresshydrationwarning

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Mohamed Iqzas