⚠️

MUI を使った開発で遭遇したコンソールログの warning

2025/02/13に公開

こんにちは、steshima です。

ソーシャル PLUS のフロントエンドでは UI フレームワークに MUI を採用しています。

MUI での開発中、時々ブラウザのコンソールにレイアウト関連の warning のログが出力されることがありますが、どういったものがあったかな?とふと思ったので備忘録としてまとめてみました。

MUI のバージョンは 5.15.10 です。

validateDOMNesting warning

Warning: validateDOMNesting(...): <p> cannot appear as a descendant of <p>.

これは MUI ではなく React(v18.2.0 使用)が出しているログで、正しくマークアップできておらず DOM 構造に問題があるときに発生します。

上記警告メッセージの場合だと、<p> の中に <p> が存在しており HTML の構造として不適切なため警告が出ています。

開発中に遭遇したパターンとしては、Typography をカスタムコンポーネントでラップしていた場合に、気づかず childrenTypography を渡してしまう、ということがありました。

import { Help } from '@mui/icons-material';
import { Stack, Typography, Tooltip } from '@mui/material';

interface Props {
  readonly helpText: string;
}

const TypographyWithHelpTooltip: React.FC<
  React.PropsWithChildren<Props>
> = ({ helpText, children }) => (
  <Stack direction="row" alignItems="center">
    <Typography>{children}</Typography>
    <Tooltip title={helpText}>
      <Help />
    </Tooltip>
  </Stack>
);

// `<p>` の中に `<p>` が render され警告が出る
<TypographyWithHelpTooltip ...>
  <Typography>hoge</Typography>
</TypographyWithHelpTooltip>

その他、警告が起きやすそうなタグで render されるコンポーネントも注意すると良さそうです。
例えば、ListItemTextAlertTitle<p> で render されます。

ref に関する warning

Warning: Function components cannot be given refs.
Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Warning: Failed prop type: Invalid prop `component` supplied to `ForwardRef(ButtonBase)`.
Expected an element type that can hold a ref. Did you accidentally provide a plain function component instead?
For more information see https://mui.com/r/caveat-with-refs-guide

上記は MUI のコンポーネントの component prop にカスタムコンポーネントを渡す時などに発生します。

原因としては、MUI のコンポーネントの一部は内部で ref を使って DOM ノードにアクセスすることがあり、そのためカスタムコンポーネントは ref を受け取れるようになっている必要があります。

2個目の警告メッセージの末尾に MUI へのリンクがあり、こちらに詳細が記載されています。
https://mui.com/material-ui/guides/composition/#caveat-with-refs

例えば Button コンポーネントの場合、下記の <MyButton> は ref を受け取っていないため、warning が発生します。

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

const MyButton: React.FC = () => <button>ボタン</button>;

// ❌ warning が発生する
<Button component={MyButton} />

下記のように ref を受けとることで解消されます。

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

interface Props {
  readonly ref?: React.Ref<HTMLButtonElement>;
  ...
}

// React 18 の記述で、React 19 からは `forwardRef` は不要
const MyButton: React.FC<Props> = React.forwardRef((props, ref) => (
  <button {...props} ref={ref} />
));

// ✅ 正しく動作する(warning が発生しない)
<Button component={MyButton} />

カスタムコンポーネントで ref を受け取るようにする必要がある MUI のコンポーネントは、ドキュメントの component prop 部分に記載があるみたいですね。
例えば Button であれば、継承元の ButtonBase API のドキュメントに記述があります。
https://v5.mui.com/material-ui/api/button-base/

Tooltip の warning

MUI: You are providing a disabled `button` child to the Tooltip component.
A disabled element does not fire events.
Tooltip needs to listen to the child element's events to display the title.

あまり起きないかもしれませんが、開発中に上記にも遭遇しました。

これは警告文の通りですが、Tooltip コンポーネントの children に disabled な Button を渡すと、disabled が設定された <button>onMouseEnter, onMouseLeave などのイベントを発火しないため、ツールチップが表示されません。

実際には、下記のようなコピーボタンの実装時に遭遇しました。

警告文の通り、disabled 属性を持たない <span> などで囲うことでツールチップが表示され、 warning が解消されます。

import {
  IconButton,
  Tooltip,
} from '@mui/material';
import { ContentCopy } from '@mui/icons-material';

interface Props {
  readonly disabled: boolean;
  ...
}

// ❌ `disabled: true` の場合 warning が発生し、ツールチップが表示されない
const CustomComponent: React.FC<Props> = ({
  disabled,
  ...
}) => (
  <Tooltip title="コピー" placement="top">
    <IconButton disabled={disabled} ...>
      <ContentCopy />
    </IconButton>
  </Tooltip>
);

// ✅ ツールチップが表示され、warning が解消される
const CustomComponent: React.FC<Props> = ({
  disabled,
  ...
}) => (
  <Tooltip title="コピー" placement="top">
    <span>
       <IconButton disabled={disabled} ...>
          <ContentCopy />
       </IconButton>
    </span>
  </Tooltip>
);

最後に

以上、今まで開発中に遭遇したものをまとめてみました。
コンソールの警告文は気づきにくく、挙動に問題ないものもあるので、是非注意してみてください。

SocialPLUS Tech Blog

Discussion