跳到内容
+

Next.js 集成

了解如何在 Next.js 中使用 Material UI。

App Router

本节介绍 Material UI 与 Next.js App Router 的集成,它是 Pages Router 的演进,并且是目前从版本 13 开始构建新的 Next.js 应用程序的推荐方式。

安装依赖

首先确保您已经安装了 @mui/materialnext。然后,运行以下命令之一来安装依赖项

npm install @mui/material-nextjs @emotion/cache

配置

app/layout.tsx 中,导入 AppRouterCacheProvider 并将其包裹在 <body> 下的所有元素

app/layout.tsx
+import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
 // or `v1X-appRouter` if you are using Next.js v1X

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

自定义缓存(可选)

使用 options prop 覆盖默认的 缓存选项——例如,下面的代码片段展示了如何将 CSS 键更改为 css(默认为 mui

  <AppRouterCacheProvider
+   options={{ key: 'css' }}
  >
    {children}
  </AppRouterCacheProvider>

字体优化

要将 Next.js 字体优化 与 Material UI 集成,请创建一个包含 'use client'; 指令的新文件。然后使用 var(--font-roboto) 作为 typography.fontFamily 字段的值创建一个主题。

src/theme.ts
'use client';
import { createTheme } from '@mui/material/styles';

const theme = createTheme({
  typography: {
    fontFamily: 'var(--font-roboto)',
  },
});

export default theme;

最后,在 src/app/layout.tsx 中,将主题传递给 ThemeProvider

app/layout.tsx
 import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
+import { Roboto } from 'next/font/google';
+import { ThemeProvider } from '@mui/material/styles';
+import theme from '../theme';

+const roboto = Roboto({
+  weight: ['300', '400', '500', '700'],
+  subsets: ['latin'],
+  display: 'swap',
+  variable: '--font-roboto',
+});

 export default function RootLayout(props) {
   const { children } = props;
   return (
+    <html lang="en" className={roboto.variable}>
       <body>
          <AppRouterCacheProvider>
+           <ThemeProvider theme={theme}>
              {children}
+           </ThemeProvider>
          </AppRouterCacheProvider>
       </body>
     </html>
   );
 }

要了解有关主题的更多信息,请查看 主题指南 页面。

CSS 主题变量

要使用 CSS 主题变量,请启用 cssVariables 标志

src/theme.ts
 'use client';
 const theme = createTheme({
+  cssVariables: true,
 });

了解更多关于 CSS 主题变量的优势 以及如何 防止 SSR 闪烁

使用其他样式解决方案

如果您正在使用 Emotion 以外的样式解决方案来自定义 Material UI 组件,请在 options prop 中设置 enableCssLayer: true

<AppRouterCacheProvider options={{ enableCssLayer: true }}>

此选项确保 Material UI 生成的样式将包裹在 CSS @layer mui 规则中,当 Material UI 与 CSS Modules、Tailwind CSS 甚至不使用 @layer 的纯 CSS 一起使用时,匿名层样式会覆盖该规则。

要了解更多信息,请参阅 MDN CSS 层文档

Pages Router

本节介绍 Material UI 与 Next.js Pages Router 的集成,适用于 服务器端渲染 (SSR) 和 静态站点生成 (SSG)。

安装依赖

首先确保您已经安装了 @mui/materialnext。然后,运行以下命令之一来安装依赖项

npm install @mui/material-nextjs @emotion/cache @emotion/server

配置

pages/_document.tsx 文件中

  • 导入 documentGetInitialProps 并将其用作 Document 的 getInitialProps
  • 导入 DocumentHeadTags 并在 <Head> 中渲染它。
pages/_document.tsx
+import {
+  DocumentHeadTags,
+  documentGetInitialProps,
+} from '@mui/material-nextjs/v15-pagesRouter';
 // or `v1X-pagesRouter` if you are using Next.js v1X

 export default function MyDocument(props) {
   return (
     <Html lang="en">
       <Head>
+        <DocumentHeadTags {...props} />
         ...
       </Head>
       <body>
         <Main />
         <NextScript />
       </body>
     </Html>
   );
 }

+MyDocument.getInitialProps = async (ctx) => {
+  const finalProps = await documentGetInitialProps(ctx);
+  return finalProps;
+};

然后,在 pages/_app.tsx 中,导入 AppCacheProvider 组件并将其渲染为根元素

pages/_app.tsx
+import { AppCacheProvider } from '@mui/material-nextjs/v15-pagesRouter';
 // Or `v1X-pages` if you are using Next.js v1X

 export default function MyApp(props) {
   return (
+    <AppCacheProvider {...props}>
       <Head>
         ...
       </Head>
       ...
+    </AppCacheProvider>
   );
 }

自定义缓存(可选)

要使用自定义的 Emotion 缓存,请将其传递给 _document.tsx 中的 emotionCache 属性

pages/_document.tsx
 ...

 MyDocument.getInitialProps = async (ctx) => {
   const finalProps = await documentGetInitialProps(ctx, {
+    emotionCache: createCustomCache(),
   });
   return finalProps;
 };

App 增强功能(可选)

将数组传递给 plugins 属性以使用附加功能增强应用程序,例如,如果您正在使用 JSS 和 styled-components,则可以使用服务器端渲染的样式。

每个插件都必须具有以下属性

  • enhanceApp:一个高阶组件,它接收 App 组件并返回一个新的 app 组件。
  • resolveProps:一个函数,它接收初始 props 并返回一个新的 props 对象。

运行时,首先从上到下调用每个插件的 enhanceApp,然后对 resolveProps 重复该过程。

import { ServerStyleSheet } from 'styled-components';

MyDocument.getInitialProps = async (ctx) => {
  const jssSheets = new JSSServerStyleSheets();
  const styledComponentsSheet = new ServerStyleSheet();

  try {
    const finalProps = await documentGetInitialProps(ctx, {
      emotionCache: createEmotionCache(),
      plugins: [
        {
          // styled-components
          enhanceApp: (App) => (props) =>
            styledComponentsSheet.collectStyles(<App {...props} />),
          resolveProps: async (initialProps) => ({
            ...initialProps,
            styles: [
              styledComponentsSheet.getStyleElement(),
              ...initialProps.styles,
            ],
          }),
        },
        {
          // JSS
          enhanceApp: (App) => (props) => jssSheets.collect(<App {...props} />),
          resolveProps: async (initialProps) => {
            const css = jssSheets.toString();
            return {
              ...initialProps,
              styles: [
                ...initialProps.styles,
                <style
                  id="jss-server-side"
                  key="jss-server-side"
                  // eslint-disable-next-line react/no-danger
                  dangerouslySetInnerHTML={{ __html: css }}
                />,
                <style id="insertion-point-jss" key="insertion-point-jss" />,
              ],
            };
          },
        },
      ],
    });
    return finalProps;
  } finally {
    styledComponentsSheet.seal();
  }
};

TypeScript

如果您正在使用 TypeScript,请将 DocumentHeadTagsProps 添加到 Document 的 props 接口

+import type { DocumentHeadTagsProps } from '@mui/material-nextjs/v15-pagesRouter';
 // or `v1X-pagesRouter` if you are using Next.js v1X

+export default function MyDocument(props: DocumentProps & DocumentHeadTagsProps) {
   ...
 }

字体优化

要将 Next.js 字体优化 与 Material UI 集成,请打开 pages/_app.tsx 并使用 var(--font-roboto) 作为 typography.fontFamily 字段的值创建一个主题。

pages/_app.tsx
 import * as React from 'react';
 import Head from 'next/head';
 import { AppProps } from 'next/app';
 import { AppCacheProvider } from '@mui/material-nextjs/v15-pagesRouter';
+import { ThemeProvider, createTheme } from '@mui/material/styles';
+import { Roboto } from 'next/font/google';

+const roboto = Roboto({
+  weight: ['300', '400', '500', '700'],
+  subsets: ['latin'],
+  display: 'swap',
+  variable: '--font-roboto',
+});

+const theme = createTheme({
+  typography: {
+    fontFamily: 'var(--font-roboto)',
+  },
+});

 export default function MyApp(props: AppProps) {
  const { Component, pageProps } = props;
  return (
    <AppCacheProvider {...props}>
      <Head>...</Head>
+     <ThemeProvider theme={theme}>
+       <main className={roboto.variable}>
          <Component {...pageProps} />
+       </main>
+     </ThemeProvider>
    </AppCacheProvider>
  );
 }

要了解有关主题的更多信息,请查看 主题指南

CSS 主题变量

要使用 CSS 主题变量,请启用 cssVariables 标志

src/theme.ts
 'use client';
 const theme = createTheme({
+  cssVariables: true,
 });

了解更多关于 CSS 主题变量的优势 以及如何 防止 SSR 闪烁