[React / Next.js / Error] MUIの styled 宣言にServer Errorのエラー

[React / Next.js / Error] MUIの styled 宣言にServer Errorのエラー

概要

  • ReactにMUIのPaperをstyled 宣言したところで次の『Server Error』エラーが発生しました。
  • エラーの原因と対応の手順をまとめました。

開発環境

  • React 19.0.0-rc-69d4b800-20241021
  • Next.js 15.0.1
  • MUI 6.1.6

エラー内容

  • Next.jsのプロジェクトで http://localhost:3000/test のページを作成。
  • 次のMUIのドキュメントページからPaperをstyled定義するコードを
    page.tsx にコピーして実行したら『Server Error』が発生しました。
  • コードを参考にした場所のURLは ↓ です。
    https://mui.com/material-ui/react-grid2/#inheriting-spacing
src\app\test\page.tsx
import {Box, Paper} from '@mui/material';
import { styled } from '@mui/material/styles';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: theme.palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));

export default function Home() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <div><Item>Test</Item></div>
    </Box>
  );
}

参考

原因

  • エラー内容で確認すると、
    1. サーバーからdefault()をコールしようとしていますが、defaultはクライアント側にあります。
    2. サーバーからクライアントの関数を呼び出すことはできない。
    3. Component側にするか、クライアントComponentにpropsとしで渡す
  • とのことでした。
Server Error
Error: 
Attempted to call default() from the server but default 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.

対応

  • Paperのstyled定義をclientで行うために既存のPaperをstyled定義処理を削除、
    client処理用ファイル styles.tsx を作成して移動します。
src\app\test\page.tsx
import {Box, Paper} from '@mui/material';
import { styled } from '@mui/material/styles';

// Parerをstyled定義を削除
/*
const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: theme.palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));
**/

export default function Home() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <div className="border-solid border-2"><Item>Test</Item></div>
    </Box>
  );
}
src\app\test\styles.tsx
// Parerをstyled定義処理をそのまま移動
import {Paper} from '@mui/material';
import { styled } from '@mui/material/styles';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: theme.palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));
  • 続けて styles.tsx に次の修正を行います。
    • ファイルの最初に"use client"; を追記することでクライアント側で処理することを宣言します。
    • page.tsx で利用できるようにするために Paperをstyled定義の前に exportを追記します。
src\app\test\styles.tsx
// クライアント側で処理することを宣言します。
"use client";
import {Paper} from '@mui/material';
import { styled } from '@mui/material/styles';

// exportを追記することでほかの場所から利用できるようにします。
export const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: theme.palette.text.secondary,
  ...theme.applyStyles('dark', {
    backgroundColor: '#1A2027',
  }),
}));
  • 次のimportを追記して styles.tsx から定義したItemを呼び出します。
  • Itemを呼び出す styles.tsx のパスは .tsxは付けない
    ことに注意してください。
import {Item} from './styles';
src\app\test\page.tsx
import {Box} from '@mui/material';
// styles.tsxからItemを呼び出します。
import {Item} from './styles';

export default function Home() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <div className="border-solid border-2"><Item>Test</Item></div>
    </Box>
  );
}
  • これで http://localhost:3000/test に接続すると次のように画面が正常に表示されました。