MUI を使った開発で遭遇したコンソールログの warning
こんにちは、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
をカスタムコンポーネントでラップしていた場合に、気づかず children
に Typography
を渡してしまう、ということがありました。
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 されるコンポーネントも注意すると良さそうです。
例えば、ListItemText
や AlertTitle
は <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 へのリンクがあり、こちらに詳細が記載されています。
例えば 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 のドキュメントに記述があります。
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>
);
最後に
以上、今まで開発中に遭遇したものをまとめてみました。
コンソールの警告文は気づきにくく、挙動に問題ないものもあるので、是非注意してみてください。
Discussion