Next.js 整合
了解如何在 Next.js 中使用 Material UI。
App Router
本節將逐步介紹 Material UI 與 Next.js App Router 的整合,它是 Pages Router 的進化版,也是目前從版本 13 開始建構新 Next.js 應用程式的建議方式。
安裝依賴套件
首先,請確保您已安裝 @mui/material
和 next
。然後,執行下列其中一個指令來安裝依賴套件
npm install @mui/material-nextjs @emotion/cache
設定
在 app/layout.tsx
內,匯入 AppRouterCacheProvider
並使用它包裹 <body>
下的所有元素
+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
欄位的值來建立主題。
'use client';
import { createTheme } from '@mui/material/styles';
const theme = createTheme({
typography: {
fontFamily: 'var(--font-roboto)',
},
});
export default theme;
最後,在 src/app/layout.tsx
中,將主題傳遞給 ThemeProvider
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
標誌
'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/material
和 next
。然後,執行下列其中一個指令來安裝依賴套件
npm install @mui/material-nextjs @emotion/cache @emotion/server
設定
在 pages/_document.tsx
檔案中
- 匯入
documentGetInitialProps
並將其用作 Document 的getInitialProps
。 - 匯入
DocumentHeadTags
並在<Head>
內呈現它。
+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
組件並將其呈現為根元素
+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
屬性
...
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
欄位的值來建立主題。
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
標誌
'use client';
const theme = createTheme({
+ cssVariables: true,
});
深入了解 CSS 主題變數的優點 以及如何防止 SSR 閃爍。