16

I've got an error while do migration to next 13 on my old project written in next 12.

Console Error Log

I can't find fault in my code for that errors. And I googled it but i can't find any solution for this. It don't explains any errors for my code. How can I solve it?

I couldn't try anything because it do not explains any error for my code. Please let me know what is the origin for that error. Thank you.

++++++++++ navigation.js

function useRouter() {
    const router = (0, _react).useContext(_appRouterContext.AppRouterContext);
    if (router === null) {
        throw new Error('invariant expected app router to be mounted');
    }
    return router;
}

i think "next/navigation" contains this file (navigation.js)

this error threw when router is null, but i still can't know why router is null.

+++++++++++ layout.jsx

"use client";

import { motion, AnimatePresence } from "framer-motion";
import "animate.css";
import { useRouter } from "next/navigation";
import LoadingSpinner from "../components/layout/media/LoadingSpinner";

import Users from "../class/Users.class";

import { useEffect } from "react";
import create from "zustand";

import Head from "next/head";
import Image from "next/image";

import NavBar from "../components/layout/NavBar";
import SubTransition from "../components/transition/SubTransition";
import LoginModal from "../components/layout/LoginModal";

import "../styles/betconstruct_icons.css";
import "../styles/global.css";

const useStore = create(() => ({
  isShowLoginModal: false,
  isLoading: true,
}));

//default layout
function MainLayout({ children }) {
  

  useEffect(() => {
    Users.checkToken().then((res) => {
      if (res) {
        console.log("token is valid");
      } else {
        console.log("token is invalid");
      }
      LoadingDone();
    });
    //router.events.on("routeChangeStart", (url) => {
    //  LoadingNow();
    //});
    //router.events.on("routeChangeComplete", () => LoadingDone());
    //router.events.on("routeChangeError", () => LoadingDone());

    if (router.pathname === "/") {
      document.querySelector("body").classList.add("layout-bc");
      document.querySelector("body").classList.add("theme-default");
      document.querySelector("body").classList.add("smart-panel-is-visible");
      document.querySelector("body").classList.add("betslip-Hidden");
      document.querySelector("body").classList.add("is-home-page");
    }

    if (router.pathname !== "/") {
      document.querySelector("body").classList.add("layout-bc");
      document.querySelector("body").classList.add("theme-default");
      document.querySelector("body").classList.add("smart-panel-is-visible");
      document.querySelector("body").classList.add("betslip-Hidden");
      document.querySelector("body").classList.add("is-home-page");
    }
  }, []);

  const animate = {
    initial: {
      opacity: 0,
      transition: `transform 0.24s ease`,
    },
    animate: {
      opacity: 1,
      transition: `transform 0.24s ease`,
    },
    exit: {
      opacity: 0,
      transition: `transform 0.24s ease`,
    },
  };

  const animateFlyIn = {
    initial: {
      opacity: 0,
      x: 100,
      transition: `transform 0.24s ease`,
    },
    animate: {
      opacity: 1,
      x: 0,
      transition: `transform 0.24s ease`,
    },
    exit: {
      opacity: 0,
      x: 100,
      transition: `transform 0.24s ease`,
    },
  };

  const { isShowLoginModal, isLoading } = useStore();
  const openLoginModal = () => {
    useStore.setState({ isShowLoginModal: true });
  };
  const hideLoginModal = () => {
    useStore.setState({ isShowLoginModal: false });
  };
  const LoadingNow = () => {
    useStore.setState({ isLoading: true });
  };

  const LoadingDone = () => {
    useStore.setState({ isLoading: false });
  };

  const router = useRouter();

  return (
    <>
      <AnimatePresence exitBeforeEnter mode={"wait"}>
        {isLoading ? (
          <motion.div
            key={router.route}
            initial={animate.initial}
            animate={animate.animate}
            exit={animate.exit}
          >
            <LoadingSpinner router={router} />
          </motion.div>
        ) : null}

        {isShowLoginModal && (
          <LoginModal
            openLoginModal={openLoginModal}
            isShowLoginModal={isShowLoginModal}
            hideLoginModal={hideLoginModal}
            LoadingNow={LoadingNow}
            LoadingDone={LoadingDone}
          />
        )}
      </AnimatePresence>
      <NavBar
        isLoading={isLoading}
        isShowLoginModal={isShowLoginModal}
        openLoginModal={openLoginModal}
        hideLoginModal={hideLoginModal}
        LoadingNow={LoadingNow}
        LoadingDone={LoadingDone}
        router={router}
      />
      <SubTransition>
        <div className="layout-content-holder-bc">{children}</div>
      </SubTransition>
    </>
  );
}

export default MainLayout;

+++ This error not occurs for /pages directory. only occurs in using /app directory

Evans Benedict
  • 276
  • 1
  • 1
  • 7

8 Answers8

71

Happened to me when layout.tsx didn't have <body> and <html> tag.

Edit:

Here is the exact section from documentation

The root layout must define <html> and <body> tags since Next.js does not automatically create them.

gazdagergo
  • 6,187
  • 1
  • 31
  • 45
Ayhan APAYDIN
  • 850
  • 5
  • 7
8

While transferring the files to the new app the same error popped up which led me to believe it was something in the code I copied over. The issue was in my layout.tsx file that was causing hydration / mounting issues because of a dom mismatch.

Old layout causing bug

export default function RootLayout({ children}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
    <div className={styles.container}>
      <header className={styles.header}>
          <>
            <Image
              priority
              src="/images/profile.jpg"
              className={utilStyles.borderCircle}
              height={144}
              width={144}
              alt=""
            />
            <h1 className={utilStyles.heading2Xl}>{name}</h1>
          </>
      </header>
      <main>{children}</main>
    </div>
    </html>
  );

Fixed code in layout.tsx

export default function RootLayout({ children}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
    <head className={styles.header}>
    </head>
    <body>{children}</body>
    </html>
  );
}

Even better: reference layout from beta docs

export default function RootLayout({ children }) {
  return (
    <html lang="en">
    {
    }
    <head />
    <body>{children}</body>
    </html>
  );
}

**Errors for reference if anyone else is encountering this problem.

Uncaught Error: invariant expected app router to be mounted

react-dom.development.js:21494 The above error occurred in the component:
at HotReload (webpack-internal:///./node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:19:11)**
Evans Benedict
  • 276
  • 1
  • 1
  • 7
3

The top-most layout is called the Root Layout. This required layout is shared across all pages in an application. Root layouts must contain html and body tags.

export default function RootLayout({ children }: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Sources:

mjuopperi
  • 773
  • 7
  • 25
1

Don't put any Wrapper Element outside body tag like this

   <AUthProvider>
    <body>
          {children}
     </body>
   </AuthProvider>

but make sure that body tag always includes all components

    <body>
       <AUthProvider>
          {children}
      <AUthProvider>
    </body>

hopefully this helps

0

I had the same problem and it was because I was wrapping my <body/> component on the layout file with another component. Apparently you shouldn't do that and instead wrap your {children} component with whatever you are wrapping your body component, just like this:

  <html lang="en">
      <body>
        <SideBar>{children}</SideBar>
      </body>
  </html>
Juan Emilio
  • 151
  • 3
  • 5
0

If you have other components inside the _app.js that you had copied over to layout.js (e.g. theme provider, redux, redux persist), it should be inside the <body> tag. Basically, it worked for me when the <body> tag was the first child of the <html> tag.

dandani-cs
  • 591
  • 1
  • 4
  • 3
0

FWIW, I had a basic loading.tsx placed at the root app level. Once I moved it into the page subfolder under app folder it started working again.

D Joyce
  • 191
  • 2
  • 12
0

I solved this problem in version 13.4.19

When you want to use app directory, you use different layers, so you must use <html></html> and <body><body /> tags in each layer.

for example

app/(home)/layout.tsx

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <body>{children}</body>
    </html>
  )
}

app/(auth)/layout.tsx

export default function AuthLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <body>{children}</body>
    </html>
  )
}