跳到主要內容
+

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 屬性來覆寫預設的 快取選項 — 例如,以下程式碼片段示範如何將 CSS key 變更為 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 屬性中設定 enableCssLayer: true

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

這個選項確保 Material UI 產生的樣式將會被包裝在 CSS @layer mui 規則中,當 Material UI 與 CSS Modules、Tailwind CSS 甚至不使用 @layer 的純 CSS 一起使用時,匿名圖層樣式會覆寫它。

若要深入了解,請參閱 MDN CSS layer 文件

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;
 };

應用程式增強功能 (選用)

將陣列傳遞至 plugins 屬性,以使用其他功能增強應用程式,例如,如果您使用 JSS 和 styled-components,則可以使用伺服器端渲染的樣式。

每個外掛程式都必須具有下列屬性

  • enhanceApp:一個高階組件,它接收 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 閃爍