next-themes icon indicating copy to clipboard operation
next-themes copied to clipboard

Next.js 13 appDir support

Open transitive-bullshit opened this issue 2 years ago • 63 comments

Opening an issue to track support for Next.js 13's appDir and server components.

Currently, it's possible to use next-themes within appDir with the following pattern:

// app/layout.tsx
import * as React from 'react'

import { Providers } from './providers'
import './globals.css'

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

      <body>
        <Providers>
          {children}
        </Providers>
      </body>
    </html>
  )
}
// app/providers.tsx
'use client'

import { ThemeProvider } from 'next-themes'

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider>
      {children}
    </ThemeProvider>
  )
}

This works for the most part, including accessing and changing the theme via useTheme.

However, during next dev, we get the following console error hinting at hydration problems:

Warning: Extra attributes from the server: data-theme,style
    at html
    at ReactDevOverlay (webpack-internal:///./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/react-dev-overlay/internal/ReactDevOverlay.js:53:9)
    at HotReload (webpack-internal:///./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:19:11)
    at Router (webpack-internal:///./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/app-router.js:74:11)
    at ErrorBoundaryHandler (webpack-internal:///./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:28:9)
    at ErrorBoundary (webpack-internal:///./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:40:11)
    at AppRouter
    at ServerRoot (webpack-internal:///./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/app-index.js:113:11)
    at RSCComponent
    at Root (webpack-internal:///./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/app-index.js:130:11)

And during production (hosted on Vercel), the following hydration errors seem to randomly appear regardless of how much I pair down the example so long as I'm using next-themes in this way:

Error: Minified React error #418; visit https://reactjs.org/docs/error-decoder.html?invariant=418 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at zh (796-3c8db907cc96f9a4.js:9:55756)
    at ...

#145 looks to be a cookies-based approach to solving this issue, but the PR looks stalled and I'm not sure if it's a working solution or even the best approach. So I wanted to open up an issue here to track suggestions & progress.

Thanks!

transitive-bullshit avatar Nov 13 '22 05:11 transitive-bullshit

Can't speak to all the issues brought up, but the hydration errors occur because of the way that next/react streams the html. If you replace the <script> tag in the ThemeScript component with the <NextScript /> component, it should hydrate correctly.

litewarp avatar Nov 14 '22 12:11 litewarp

#145 was working with an earlier build of Next.js, but it definitely looks like using <NextScript /> can clean that pr up quite a bit now. I'm gonna try to update it this week

WITS avatar Nov 16 '22 20:11 WITS

Thanks @WITS 🙏

@leerob would you be able to provide any guidance on the best solution here (or forward to someone who might)?

transitive-bullshit avatar Nov 16 '22 20:11 transitive-bullshit

That pr should be updated to work with Next.js 13.0.3 now. I'm still looking into making further improvements, but you can test the changes through the npm package @wits/next-themes prior to the pr being merged. (Or try running npm i "next-themes@npm:@wits/next-themes" if you want to keep the same imports in your code.)

I'd like to provide some more context on why the current approach uses cookies. Unfortunately, trying to get this working in the app directory without ensuring that the server is rendering the same <html> attributes results in errors. So I reached out to @pacocoursey as well as some members of the Next.js team before starting this work, and they agreed that a cookie-based approach would be the right move.

next/script is a great call! It wasn't available for the app directory when I first started writing these changes, but it looks like using it with stategy="beforeInteractive" works here. However, doing so inside of a client component (like the existing ThemeProvider still causes it to run too late and the page will flicker un-themed content. Also, by default, that script relies on window.matchMedia to determine the system theme of the user. That isn't available on the server, so without cookies we still get errors due to a mismatch between client and server rendering during fast refreshes.

Update: Please make sure you use the <ServerThemeProvider> (as outlined here) if you're trying this out. If you want to have theme switcher UI, you'll need both the <ServerThemeProvider> in the layout and a <ThemeProvider> in an interactive ("use client") component.

Update 2: The fork above is no longer being maintained! Please see this comment for instructions on how to use the stable version of next-themes with appDir.

WITS avatar Nov 17 '22 18:11 WITS

Appreciate the in-depth breakdown @WITS.

I just tried @wits/next-themes on my project, and while I can verify it's taking effect, I'm not seeing any changes with regards to the error messages. On next dev, the same hydration error occurs w.r.t. extra html attributes, and on production, the same hydration errors appear sporadically (same as previously).

This could be a problem with my app, of course, but the hydration errors during next dev give me pause.

transitive-bullshit avatar Nov 17 '22 22:11 transitive-bullshit

Would you be able to share your updated app/layout.tsx (or a simplified version of it) so I can reproduce the issue locally?

WITS avatar Nov 17 '22 22:11 WITS

Definitely not a minimal repro, but my source is here: https://github.com/transitive-bullshit/next-movie/blob/main/app/layout.tsx. See RootLayoutProviders.

I currently have my usage of next-themes commented out in the providers and in a few places in the code because no matter what I tried, I would get sporadic hydration errors on prod that would cause the entire client-side JS to stop working — resulting in a dead app for users. It should be easy to re-enable once next-themes is patched.

transitive-bullshit avatar Nov 18 '22 07:11 transitive-bullshit

Ah, I should have clarified when I explained the approach above that it requires a new component. Can you try wrapping the <html> tag in your layout.tsx file with the <ServerThemeProvider> from @wits/next-themes and see if that works?

(There's a section in the updated README with an example.)

WITS avatar Nov 18 '22 17:11 WITS

Ahhh good catch.

Okay, so after doing that and re-enabling my usage of next-themes@npm:@wits/themes, I'm seeing the following.

Dev

During next dev the first few times it loads is fine, but as soon as I toggle dark mode client-side and hard refresh, I start seeing mismatched hydration warnings in the dev console:

CleanShot 2022-11-18 at 17 59 54@2x CleanShot 2022-11-18 at 18 00 04@2x

Prod

It works well hydration-wise 💯 I haven't been able to reproduce any hydration errors when deployed as a preview build to Vercel: https://next-movie-hrwhglaz6-saasify.vercel.app/

However, I'm now seeing different, consistent 500 errors from Vercel using this branch with next-themes enabled that doesn't repro on main:

Error: invariant: invalid Cache-Control duration provided: 0 < 1

CleanShot 2022-11-18 at 18 10 06@2x

Example: https://next-movie-hrwhglaz6-saasify.vercel.app/titles/424

@WITS I'm going to hold off on re-enabling dark mode toggle in prod for now. I'm not too worried about the next dev errors, so long as it works on prod, though we should probably get them fixed before merging #145. If you want to test locally, check out https://github.com/transitive-bullshit/next-movie/tree/feature/next-themes-beta and set DATABASE_URL to a Postgres instance. You may also need to do npx prisma db push or npx prisma generate.

I think this cache-control issue invariant issue is likely a bug with next@canary, though it's strange that it only repros on this branch where the only changes involve enabling next-themes.

transitive-bullshit avatar Nov 19 '22 00:11 transitive-bullshit

I created a few Next.js issues to track the errors I'm running into. Not sure what else I can do to help.

transitive-bullshit avatar Nov 20 '22 22:11 transitive-bullshit

image

[0] event - compiled client and server successfully in 837 ms (350 modules)
[0] wait  - compiling /_error (client and server)...
[0] error - (sc_server)/node_modules/.pnpm/[email protected]_7iuvftg57tblwyxclfkwku5xo4/node_modules/next-themes/dist/index.js (1:223) @ eval
[0] error - TypeError: e.createContext is not a function
[0]     at eval (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_7iuvftg57tblwyxclfkwku5xo4/node_modules/next-themes/dist/index.js:11:92)
[0]     at Object.(sc_server)/./node_modules/.pnpm/[email protected]_7iuvftg57tblwyxclfkwku5xo4/node_modules/next-themes/dist/index.js (/Users/v0/Sites/alpha/.next/server/app/[locale]/page.js:345:1)
[0]     at __webpack_require__ (/Users/v0/Sites/alpha/.next/server/webpack-runtime.js:33:42)
[0]     at eval (webpack-internal:///(sc_server)/./app/[locale]/themes.tsx:11:69)
[0]     at Object.(sc_server)/./app/[locale]/themes.tsx (/Users/v0/Sites/alpha/.next/server/app/[locale]/page.js:313:1)
[0]     at __webpack_require__ (/Users/v0/Sites/alpha/.next/server/webpack-runtime.js:33:42)
[0]     at eval (webpack-internal:///(sc_server)/./app/[locale]/page.tsx:6:65)
[0]     at Object.(sc_server)/./app/[locale]/page.tsx (/Users/v0/Sites/alpha/.next/server/app/[locale]/page.js:292:1)
[0]     at Function.__webpack_require__ (/Users/v0/Sites/alpha/.next/server/webpack-runtime.js:33:42)
[0]     at processTicksAndRejections (node:internal/process/task_queues:96:5) {
[0]   type: 'TypeError',
[0]   page: '/[locale]'
[0] }

willin avatar Nov 25 '22 13:11 willin

That pr should be updated to work with Next.js 13.0.3 now. I'm still looking into making further improvements, but you can test the changes through the npm package @wits/next-themes prior to the pr being merged. (Or try running npm i "next-themes@npm:@wits/next-themes" if you want to keep the same imports in your code.)

I'd like to provide some more context on why the current approach uses cookies. Unfortunately, trying to get this working in the app directory without ensuring that the server is rendering the same <html> attributes results in errors. So I reached out to @pacocoursey as well as some members of the Next.js team before starting this work, and they agreed that a cookie-based approach would be the right move.

next/script is a great call! It wasn't available for the app directory when I first started writing these changes, but it looks like using it with stategy="beforeInteractive" works here. However, doing so inside of a client component (like the existing ThemeProvider still causes it to run too late and the page will flicker un-themed content. Also, by default, that script relies on window.matchMedia to determine the system theme of the user. That isn't available on the server, so without cookies we still get errors due to a mismatch between client and server rendering during fast refreshes.

image
[0] event - compiled client and server successfully in 655 ms (199 modules)
[0] wait  - compiling /middleware (client and server)...
[0] event - compiled successfully in 51 ms (67 modules)
[0] wait  - compiling /[locale]/page (client and server)...
[0] event - compiled client and server successfully in 440 ms (362 modules)
[0] TypeError: Cannot read properties of undefined (reading '_context')
[0]     at Object.useContext (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react/cjs/react.shared-subset.development.js:1418:29)
[0]     at exports.useTheme (webpack-internal:///(sc_server)/./node_modules/.pnpm/@[email protected]_7iuvftg57tblwyxclfkwku5xo4/node_modules/@wits/next-themes/dist/index.js:215:28)
[0]     at ChangeTheme (webpack-internal:///(sc_server)/./app/[locale]/themes.tsx:147:84)
[0]     at attemptResolveElement (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1207:42)
[0]     at resolveModelToJSON (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1660:53)
[0]     at Object.toJSON (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1121:40)
[0]     at stringify (<anonymous>)
[0]     at processModelChunk (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:172:36)
[0]     at retryTask (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1868:50)
[0]     at performWork (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1906:33)
[0] TypeError: Cannot read properties of undefined (reading '_context')
[0]     at Object.useContext (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react/cjs/react.shared-subset.development.js:1418:29)
[0]     at exports.useTheme (webpack-internal:///(sc_server)/./node_modules/.pnpm/@[email protected]_7iuvftg57tblwyxclfkwku5xo4/node_modules/@wits/next-themes/dist/index.js:215:28)
[0]     at ChangeTheme (webpack-internal:///(sc_server)/./app/[locale]/themes.tsx:147:84)
[0]     at attemptResolveElement (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1207:42)
[0]     at resolveModelToJSON (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1660:53)
[0]     at Object.toJSON (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1121:40)
[0]     at stringify (<anonymous>)
[0]     at processModelChunk (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:172:36)
[0]     at retryTask (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1868:50)
[0]     at performWork (webpack-internal:///(sc_server)/./node_modules/.pnpm/[email protected]_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1906:33) {
[0]   digest: '3476920131'
[0] }

willin avatar Nov 25 '22 13:11 willin

@WITS Hi, I am using the @wits/next-themes ServerThemeProvider, but I still get the same hydration error. Not sure what the problem might be. Here's the code snippet (it's a fresh project).

const RootLayout = ({ children }: IProps) => {
  return (
    <ServerThemeProvider>
      <html lang="en">
        <head />

        <Providers>
          <body className="bg-red-500 dark:bg-blue-500">{children}</body>
        </Providers>
      </html>
    </ServerThemeProvider>
  );
};

After adding attribute='class' props to the provider the hydration still error persists, but is displayed after this error Cannot read properties of null (reading 'textContent'). Any help would be appreciated :)

dawidseipold avatar Nov 30 '22 05:11 dawidseipold

I published a new version of @wits/next-themes (0.2.13) today that includes some fixes.

@transitive-bullshit Good catch! The "e" value was due to a bug in my pr, and should be fixed now. However, I can still reproduce the hydration issues whenever I explicitly set the theme to something other than system. I think this might be an issue with Next caching the first value it receives for the cookie after the server starts. I'm going to investigate further and reach out to them if that's the case.

@willin Is your project using <ServerThemeProvider> in the layout?

@dawidseipold Are you using the same properties on your <ServerThemeProvider> as your <ThemeProvider>? (If you're setting attribute="class" on one, it needs to be on both.)

WITS avatar Nov 30 '22 23:11 WITS

@WITS Yep! The hydration error is doubled if I do that. Having only <ServerThemeProvider> gives me one error.

dawidseipold avatar Dec 01 '22 01:12 dawidseipold

Okay, just published 0.2.14 which should fix more hydration errors. (Maybe all of them? 🤞)

WITS avatar Dec 01 '22 21:12 WITS

Okay, just published 0.2.14 which should fix more hydration errors. (Maybe all of them? 🤞)

nope,

RootLayout:

      <ServerThemeProvider attribute='class' themes={themes.map((x) => x.id)}>
        <html lang={locale}>
          <head />
          <body>
            <div
              id='background'
              className={clsx({
                dark: true //darkThemes.map((x) => x.toLowerCase()).includes(theme)
              })}></div>
            {/* <Header /> */}
            <div className='pt-20' style={{ minHeight: 'calc(100vh - 75px)' }}>
              {children}
            </div>
            <Bootstrap />
          </body>
        </html>
      </ServerThemeProvider>

Component: image

image

current theme none, set theme not work.

willin avatar Dec 03 '22 10:12 willin

if a nest a ThemeProvider inside ServerThemeProvider:

image

willin avatar Dec 03 '22 10:12 willin

is there a working example using class?

willin avatar Dec 03 '22 10:12 willin

Hey @WITS, I can get the page to render using both <ServerThemeProvider /> and a client <ThemeProvider/>, but I can't get setTheme to work. I'll try and reproduce it for you. In the meantime, I noticed that when using both providers, the script gets injected twice. Not sure if this would be the cause of some issues.

image

litewarp avatar Dec 04 '22 19:12 litewarp

@willin same problem when I nest. It also shows in the console that the classes on html element are different.

dawidseipold avatar Dec 06 '22 10:12 dawidseipold

Hey @WITS, I haven't managed to get your 0.2.14 to properly function (with the ServerProvider and ThemeProvider), but it might be because I'm on Next 13.0.6?

Warning: Cannot render a sync or defer

I'd also like to get your thoughts on the cookie-based approach you elaborated above would play out with edge caching. If the page is requested once by a user with a "dark" cookie, we will likely get a flash of wrong theme if another requests the same cached page with a different cookie correct? Using localStorage was a way around that issue, but I guess Server Components might not leave us much of a choice. I don't think there's a way to use the Vary cache header on one particular cookie.

balthazar avatar Dec 12 '22 17:12 balthazar

Good news and bad news — although I think the bad news is exclusively for me, because I didn't realize this option existed before coding the cookie-based version.

I don't believe next-themes actually needs any code changes to support appDir. Using cookies opts out of SSG (and would likely lead to issues with edge caching, like @balthazar mentioned above), so I've been investigating how to solve the hydration issues without them. In doing so, I discovered React's suppressHydrationWarning property. Because layouts in the app directory render the <html> tag, they can use this property on that element. It only applies one level deep, per the documentation, so it shouldn't block problematic hydration warnings from appearing in the console. Using this & a <Providers> component, it should be possible to use the stable version of next-themes in the app directory without issues.

Example:

// app/layout.jsx

import { Providers } from "./providers";

export default function Layout({ children }) {
  return (
    <html suppressHydrationWarning>
      <head />
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
// app/providers.jsx

"use client";

import { ThemeProvider } from "next-themes";

export function Providers({ children }) {
  return <ThemeProvider>{children}</ThemeProvider>;
}

In my opinion, the only thing that would still be worth changing in next-themes to better support this would be to prepend the 'use client'; directive to the exported code. (This change would eliminate the <Providers> requirement in the example above.) Unfortunately directives get stripped out when using microbundle, so this would either need to be done via a custom script or by switching to a different bundler.

WITS avatar Dec 23 '22 19:12 WITS

Hi @WITS! Thanks for putting the time to try fix this.

I'm on the latest release of Next (13.1.1-canary.0). I've tried both your cookie-based version (which weirdly enough worked correctly for a couple of minutes before breaking again) and the solution you just posted, none of them work. I checked that the cookie-based version was correctly setup (same props as ThemeProvider).

Thing is, it only happens when I switch to 'light' mode and refresh the page, when it's in 'dark' it's working correctly. Maybe this is something related to my actual code, I am getting a strange error that I can't seem to find anything about it online.

Uncaught TypeError: wakeable.then is not a function at Object.markComponentSuspended (react_devtools_backend.js:5694:16) at markComponentSuspended (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js:5148:30) at handleThrow (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js:30642:7) at renderRootSync (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js:30854:7) at performConcurrentWorkOnRoot (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js:29978:74) at workLoop (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/scheduler/index.js:11:3897) at flushWork (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/scheduler/index.js:11:3606) at MessagePort.performWorkUntilDeadline (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/scheduler/index.js:11:1787)

However, putting the workaround -or solution- posted here in Next-themes using useEffect for checking if it's mounted on the client seems to work perfectly in the RootLayout:

const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted)
    return (
      <html>
        <head />
        <body></body>
      </html>
    );

  return (
   // ...the actual layout
  )

JuanseChavero avatar Dec 24 '22 00:12 JuanseChavero

Hi @JuanseChavero, One caveat in my project was to use the exact same layout.tsx as @WITS provided. I had some additional components inside the <body> tag, and they cased issues. Once I moved them into the page.tsx the hydration errors disappeared. Maybe this helps you.

raphaelschwinger avatar Jan 04 '23 17:01 raphaelschwinger

@WITS Hi, I am using the @wits/next-themes ServerThemeProvider, but I still get the same hydration error. Not sure what the problem might be. Here's the code snippet (it's a fresh project).

const RootLayout = ({ children }: IProps) => {
  return (
    <ServerThemeProvider>
      <html lang="en">
        <head />

        <Providers>
          <body className="bg-red-500 dark:bg-blue-500">{children}</body>
        </Providers>
      </html>
    </ServerThemeProvider>
  );
};

Does moving the Providers component within the body tags help?

huperniketes avatar Jan 10 '23 04:01 huperniketes

Hi, do you have any ideas how to enable themes (dark/light) only for particular pages? Otherwise, it should be always light theme. I was trying to do set the forcedTheme, but it causes the page flickering, as it works on client side. Any help is appreciated, thank you!

'use client';

import { usePathname } from 'next/navigation';
import { ThemeProvider as PreferredProvider } from 'next-themes';

// eslint-disable-next-line react/prop-types
const ThemeProvider = ({ children }) => {
  const pathname = usePathname();
  const isDocPage = pathname.startsWith('/docs'); 

  return (
    <PreferredProvider attribute="class" forcedTheme={isDocPage ? null : 'light'}>
      {children}
    </PreferredProvider>
  );
};
export default ThemeProvider;

vannyle avatar Jan 19 '23 10:01 vannyle

Uncaught TypeError: wakeable.then is not a function at Object.markComponentSuspended (react_devtools_backend.js:5694:16) at markComponentSuspended (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js:5148:30) at handleThrow (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js:30642:7) at renderRootSync (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js:30854:7) at performConcurrentWorkOnRoot (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/react-dom/cjs/react-dom.development.js:29978:74) at workLoop (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/scheduler/index.js:11:3897) at flushWork (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/scheduler/index.js:11:3606) at MessagePort.performWorkUntilDeadline (webpack-internal:///(:3000/app-client)/./node_modules/next/dist/compiled/scheduler/index.js:11:1787)

@JuanseChavero FYI this is a bug of React DevTools. If you disable React DevTools, the error would be gone.

There is already an issue opened: https://github.com/facebook/react/issues/25994

However, it appears that React team just doesn't want to work on this issue yet, so I have provided a workaround: https://github.com/facebook/react/issues/25994#issuecomment-1402287594

SukkaW avatar Jan 24 '23 16:01 SukkaW

I managed to fix this hydration error on next 13 using app dir with the following:


import { Header } from "@/components";
import "./globals.css";
import { ThemeProvider } from "next-themes";
import { useEffect, useState } from "react";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  return (
    <html lang="en">
      {/*
        <head /> will contain the components returned by the nearest parent
        head.tsx. Find out more at https://beta.nextjs.org/docs/api-reference/file-conventions/head
      */}
      <head />
      <body>
        {mounted && (
          <ThemeProvider enableSystem={true} attribute="class">
            <Header appName="" />
            {children}
          </ThemeProvider>
        )}
      </body>
    </html>
  );
}

ahmamedhat avatar Feb 07 '23 18:02 ahmamedhat

Screenshot 2023-02-08 at 11 26 36 PM

@WITS any recommendation of how this could be fixed?

antsav avatar Feb 09 '23 05:02 antsav