Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering

Viewed 4817

I am making a website using Next.js and the above error is shown every time.

Don't know what is wrong in my code.

const Login = () => {
  const [userMsg, setUserMsg] = useState("");
  const [email, setEmail] = useState("");
  const router=useRouter();

  const handleOnChangeEmail = (e) => {
    e.preventDefault();
    setUserMsg("");
    console.log("event", e);
    const email = e.target.value;
    setEmail(email);
  };
  const handleLoginWithEmail = (e) => {
    e.preventDefault();
    if (email) {
      if (IsEmail.validate(email)){
        router.push("/")
        
      }else{
        setUserMsg("Enter a valid email address")
      }
      
    } else {
      //show usermssg
      setUserMsg("Enter an email address");
    }
  };
  return (
    <div className="bg-[url('/static/bglg.jpg')] flex items-stretch flex-col h-screen w-full">
      <head>
        <title>NeoVest SignIn</title>
      </head>
      <header className="text-4xl px-10 py-2 font-black">
        <span className="text-indigo-700">NeoVest</span>
      </header>
      <div className="w-full max-w-xs m-auto bg-[#C9C9C9] rounded p-5 bg-opacity-50 border-gray-200">
        <header>
          <div className="text-indigo-700 font-black text-3xl py-2">
            <p>Sign In</p>
          </div>
        </header>
        <form className="py-5">
          <div>
            <label className="block mb-2 text-indigo-500" for="username">
              Email
            </label>
            <input
              className="w-full p-2 mb-6 text-indigo-700 border-b-2 border-indigo-500 outline-none focus:bg-gray-300"
              type="text"
              name="username"
              placeholder="Email Address"
              onChange={handleOnChangeEmail}
            />
            <div className="block mb-2 text-red-700">
              <p>{userMsg}</p>
            </div>
          </div>
          <div>
            <input
              className="w-full bg-indigo-700 hover:bg-pink-700 text-white font-bold py-2 px-4 mb-6 rounded"
              type="button"
              value="Submit"
              onClick={handleLoginWithEmail}
            />
          </div>
        </form>
      </div>
    </div>
  );
};

Another error shown is due to some suspense boundary causing root to switch to client side rendering :

Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.

I am also using Tailwind if that information is important.

5 Answers

If you would look at the console you would see a warning.

Warning: validateDOMNesting(...): <head> cannot appear as a child of <div>

So, to fix this you just have to move head out of the div and move it to a different higher component.

The problem is this:

<head>
    <title>NeoVest SignIn</title>
</head>

To solve it, first import Head, and then, use it with Capital "H"

import Head from "next/head"

<Head>
    <title>NeoVest SignIn</title>
</Head>

I verified some topics in my code. First, verified if in next.config.js was styled components declared.

reactStrictMode: true,
  compiler: {
    styledComponents: true,
  },

In second, I checked if file babel ".babelrc" was created in root folder with this content:

{
  "presets": ["next/babel"],
  "plugins": ["styled-components"]
}

The error yet showed. Component by component I checked and more two errors was found. First, HTML errors like this:

<!-- wrong -->
<p>
<ul></ul>
</p>
<!-- right -->
<p></p>
<ul></ul>
<p></p>
<!-- or right -->
<div>
<ul></ul>
</div>

Finally, I found an error in initializing component. In my case, I declared - incorrectly - a const items (object). The right way to execute this is using useState.

<!-- WRONG WAY THAT I WAS DID -->
const Works = () => {
  const items =  [
    {
      id: 1,
      name: 'any name',
      src: 'srcpath'
    },
    {
      id: 2,
      name: 'any name 2',
      src: 'srcpath'
    },
    {
      id: 3,
      name: 'any name 3',
      src: 'srcpath'
    },
];

return(
   items.map((item, index) => {
     return(
        <div key={index}>{item.name}</div>
     )
   }
)
});

<!-- RIGHT WAY THAT I FIXED -->
const Works = () => {
  const [ item, setItem ] = React.useState();
  React.useEffect(() => {
     setItem([
    {
      id: 1,
      name: 'any name',
      src: 'srcpath'
    },
    {
      id: 2,
      name: 'any name 2',
      src: 'srcpath'
    },
    {
      id: 3,
      name: 'any name 3',
      src: 'srcpath'
    },
   ]);
  }, []);
  
if(item)
return(
   items.map((item, index) => {
     return(
        <div key={index}>{item.name}</div>
     )
   }
)
});

Time and randomness are two of the things that most commonly produce this

as discussed in Hydration errors - Text content does not match server-rendered HTML. #38263

Possible solution might be to use useEffect hook

// Example component with an error
import React from "react";

const AllNames = ["Ali", "Elisa", "Bella", "Carmen"];

const RandomUniqueNames = Array.from({ length: 4 }).map((_, index) => {
  let randomIndex = Math.floor(Math.random() * AllNames.length);
  console.log(randomIndex);
  let name = AllNames[randomIndex];
  return {
    name,
  };
});

export default function ModernNames() {
  return (
    <div>
      <h1>ModernNames</h1>
      {RandomUniqueNames.map((name) => (
        <p>{name.name}</p>
      ))}
    </div>
  );
}

// Example solution
import React, { useState, useEffect } from "react";

const AllNames = ["Ali", "Elisa", "Bella", "Carmen"];

export default function ModernNames() {
  const [randomNames, setRandomNames] = useState([]);
  useEffect(() => {
    const RandomUniqueNames = Array.from({ length: 4 }).map((_, index) => {
      let randomIndex = Math.floor(Math.random() * AllNames.length);
      console.log(randomIndex);
      let name = AllNames[randomIndex];
      return {
        name,
      };
    });
    setRandomNames(RandomUniqueNames);
  }, []);
  return (
    <div>
      <h1>ModernNames</h1>
      {randomNames.map((name, index) => (
        <p key={index}>{name.name}</p>
      ))}
    </div>
  );
}

You can try downgrading react version. Try react@17.

Related