You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js 13中不使用"use client"兼容Material UI?

解决Next.js 13中无需给layout.jsx加"use client"即可使用Material UI的方案

问题根源是Material UI的多数组件依赖useLayoutEffect这类客户端专属API,而Next.js 13的layout.jsx默认是Server Component,直接导入MUI组件会触发客户端API在服务端执行的错误。要兼顾全局SSR和局部客户端MUI组件,核心思路是将MUI的客户端依赖隔离到单独的组件文件中,不让其渗透到Server Component层级。

方案1:封装MUI组件为独立客户端组件

把需要用到的MUI组件单独封装到带有"use client"标记的文件中,Server Component(包括layout)只导入这个封装后的组件,避免直接依赖MUI的客户端模块。

示例:

// components/ClientMuiButton.jsx
"use client";

import Button from '@mui/material/Button';

// 可直接导出原始组件,或添加自定义逻辑
export default function ClientMuiButton({ children, ...props }) {
  return <Button variant="contained" {...props}>{children}</Button>;
}

在layout.jsx中使用:

// app/layout.jsx
import ClientMuiButton from '@/components/ClientMuiButton';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {/* 这里的ClientMuiButton是客户端组件,但layout依然是Server Component */}
        <ClientMuiButton>首页按钮</ClientMuiButton>
        {children}
      </body>
    </html>
  );
}

方案2:用Next.js Dynamic导入禁用SSR

针对无需服务端渲染的交互型MUI组件(如弹窗、下拉菜单),可以使用next/dynamic动态导入并关闭SSR,组件会仅在客户端渲染,不影响Server Component的SSR特性。

示例:

// app/layout.jsx
import dynamic from 'next/dynamic';

// 动态导入MUI的Button,禁用SSR
const DynamicMuiButton = dynamic(() => import('@mui/material/Button'), {
  ssr: false,
  loading: () => <span>加载中...</span> // 可选:添加加载占位符
});

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <DynamicMuiButton>动态客户端按钮</DynamicMuiButton>
        {children}
      </body>
    </html>
  );
}

方案3:隔离MUI主题相关逻辑

如果需要全局使用MUI主题,不要在layout.jsx中直接导入ThemeProvider,而是将其封装到客户端组件中:

// components/ClientThemeProvider.jsx
"use client";

import { ThemeProvider, createTheme } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';

const customTheme = createTheme({
  palette: {
    primary: { main: '#1976d2' },
    mode: 'light'
  }
});

export default function ClientThemeProvider({ children }) {
  return (
    <ThemeProvider theme={customTheme}>
      <CssBaseline />
      {children}
    </ThemeProvider>
  );
}

在layout.jsx中使用:

// app/layout.jsx
import ClientThemeProvider from '@/components/ClientThemeProvider';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <ClientThemeProvider>
          {/* 所有子组件可使用MUI主题,且layout仍为Server Component */}
          {children}
        </ClientThemeProvider>
      </body>
    </html>
  );
}

核心原则

所有依赖客户端API(如useLayoutEffect、useState)的MUI代码,必须被包裹在带有"use client"标记的组件中,Server Component仅作为容器导入这些封装后的组件,以此实现全局SSR和局部客户端渲染的平衡。

内容的提问来源于stack exchange,提问作者Michal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:07:02