Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hydration issues still exist with NextJS when applying custom themes #40945

Closed
jamietdavidson opened this issue Feb 5, 2024 · 8 comments
Closed
Labels
duplicate This issue or pull request already exists nextjs

Comments

@jamietdavidson
Copy link

jamietdavidson commented Feb 5, 2024

Steps to reproduce

Link to live example: (required)

Steps:

  1. Create next app using next 14 and node 18
  2. install mui joy
  3. follow the steps outlined in the docs for creating a theme and preventing hydration issues

Current behavior

inside of apps/layout.tsx:

import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';

import CONSTANTS from '@/CONSTANTS';
import ThemeRegistry from '@/core/theme/ThemeRegistry';
import { getInitColorSchemeScript } from '@mui/joy';

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: CONSTANTS.COMPANY_NAME,
  description: CONSTANTS.COMPANY_DESCRIPTION,
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {

  return (
    <html lang="en" >
      <ThemeRegistry options={{ key: 'joy' }}>
        <body className={inter.className}>
          {getInitColorSchemeScript()}
          {children}</body>
      </ThemeRegistry>
    </html>
  )
}

Inside of @/core/theme/ThemeRegistry (straight from the docs), with the exception that I've added my ApolloProvider.

'use client';

import useApollo from '@/core/hooks/useApollo';
import { ApolloProvider } from '@apollo/client';
import createCache from '@emotion/cache';
import { CacheProvider } from '@emotion/react';
import CssBaseline from '@mui/joy/CssBaseline';
import { CssVarsProvider } from '@mui/joy/styles';
import { useServerInsertedHTML } from 'next/navigation';
import { useState } from 'react';
import theme from './theme';

export default function ThemeRegistry(props) {
  const { options, children } = props;
  const apolloClient = useApollo();

  const [{ cache, flush }] = useState(() => {
    const cache = createCache(options);
    cache.compat = true;
    const prevInsert = cache.insert;
    let inserted: string[] = [];
    cache.insert = (...args) => {
      const serialized = args[1];
      if (cache.inserted[serialized.name] === undefined) {
        inserted.push(serialized.name);
      }
      return prevInsert(...args);
    };
    const flush = () => {
      const prevInserted = inserted;
      inserted = [];
      return prevInserted;
    };
    return { cache, flush };
  });

  useServerInsertedHTML(() => {
    const names = flush();
    if (names.length === 0) {
      return null;
    }
    let styles = '';
    for (const name of names) {
      styles += cache.inserted[name];
    }
    return (
      <style
        key={cache.key}
        data-emotion={`${cache.key} ${names.join(' ')}`}
        dangerouslySetInnerHTML={{
          __html: styles,
        }}
      />
    );
  });

  return (
    <CacheProvider value={cache}>
      <CssVarsProvider theme={theme}>
        {/* the custom theme is optional */}
        <CssBaseline />
         <ApolloProvider client={apolloClient}>
          {children}
         </ApolloProvider>
      </CssVarsProvider>
    </CacheProvider>
  );
}
Error: Attempted to call getInitColorSchemeScript() from the server but getInitColorSchemeScript is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.```.

When moving the `getInitColorSchemeScript` inside of the first client

### Expected behavior

The error should not be preset and flickering should not occur.

### Context

Trying to have dark mode be enabled by default. Currently I am experiencing a flicker.

### Your environment

<details>
  <summary><code>npx @mui/envinfo</code></summary>

Browser: Chrome (latest version as of posting)

System:
OS: macOS 14.2.1
Binaries:
Node: 18.19.0 - ~/.nvm/versions/node/v18.19.0/bin/node
npm: 10.2.3 - ~/.nvm/versions/node/v18.19.0/bin/npm
pnpm: Not Found
Browsers:
Chrome: 121.0.6167.139
Edge: Not Found
Safari: 17.2.1
npmPackages:
@emotion/react: ^11.11.3 => 11.11.3
@emotion/styled: ^11.11.0 => 11.11.0
@mui/base: 5.0.0-beta.33
@mui/core-downloads-tracker: 5.15.6
@mui/icons-material: ^5.15.6 => 5.15.6
@mui/joy: ^5.0.0-beta.24 => 5.0.0-beta.24
@mui/material: 5.15.6
@mui/private-theming: 5.15.6
@mui/styled-engine: 5.15.6
@mui/system: ^5.15.6 => 5.15.6
@mui/types: 7.2.13
@mui/utils: 5.15.6
@types/react: ^18 => 18.2.48
react: ^18 => 18.2.0
react-dom: ^18 => 18.2.0
typescript: ^5 => 5.3.3

</details>


**Search keywords**: hydration theme
@jamietdavidson jamietdavidson added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 5, 2024
@jamietdavidson jamietdavidson changed the title Hydration issues still exist with NextJS Hydration issues still exist with NextJS when applying custom themes Feb 5, 2024
@samuelsycamore
Copy link
Contributor

samuelsycamore commented Feb 5, 2024

Hey Jamie 👋 This error message is correct:

Error: Attempted to call getInitColorSchemeScript() from the server but getInitColorSchemeScript is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.

You're calling {getInitColorSchemeScript()} in layout.tsx which is a Server Component—you'll need to add the "use client" directive to that file as well for it to work.

@samuelsycamore samuelsycamore added support: question Community support but can be turned into an improvement status: expected behavior Does not imply the behavior is intended. Just that we know about it and can't work around it nextjs and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Feb 5, 2024
@jamietdavidson
Copy link
Author

jamietdavidson commented Feb 5, 2024

Hi @samuelsycamore !

Thanks for the reply. I suppose I don't understand the mechanics of Next 14 too well yet. I am then faced with:

You are attempting to export "metadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive. Read more: https://nextjs.org/docs/getting-started/react-essentials#the-use-client-directive

Removing the export prevents my page from having a name when looking at my tabs. What would you recommend I try next?

@samuelsycamore
Copy link
Contributor

@jamietdavidson It sounds like you'll need to move the exported metadata to a Server Component. This is a Next.js specific issue, so your best bet from here would be to seek help on Stack Overflow. Best of luck! This new paradigm of Server and Client Components can be really tricky to untangle. If you don't have a specific need for the App Router, I might suggest reverting to the Pages Router so you don't have to worry about this stuff at all.

@jamietdavidson
Copy link
Author

@samuelsycamore Will do! Thanks for the timely help :)

@jamietdavidson
Copy link
Author

And awesome work on Mui Joy, it is leaps and bounds easier to work with than material. Global variants is an amazing idea, and overriding the default props within the theme is genius.

@samuelsycamore
Copy link
Contributor

Cheers @jamietdavidson! I think @siriwatknp deserves most of the praise for Joy UI so hopefully he sees this! 😁

@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 8, 2024

You're calling {getInitColorSchemeScript()} in layout.tsx which is a Server Component—you'll need to add the "use client" directive to that file as well for it to work.

@samuelsycamore getInitColorSchemeScript shouldn't need to be a client component.

@oliviertassinari oliviertassinari added duplicate This issue or pull request already exists and removed support: question Community support but can be turned into an improvement status: expected behavior Does not imply the behavior is intended. Just that we know about it and can't work around it labels Feb 8, 2024
@oliviertassinari
Copy link
Member

Duplicate of #42750

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Feb 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists nextjs
Projects
None yet
Development

No branches or pull requests

3 participants