MUI BottomNavigationAction のナビゲーションを Next.js Link で実現する
1時間くらい引っかかって中々情報が出てこなかったので、忘却後の自分と誰かのためにメモしておく。なお、意図されていない属性を使っているかも知れないので悪しからず
結論
BottomNavigationAction に用意されている LinkComponent 属性に Link コンポーネントを指定後、href 属性を設定する
import { BottomNavigation, BottomNavigationAction, Paper } from "@mui/material";
import { type SyntheticEvent, useState } from "react";
import HomeIcon from "@mui/icons-material/Home";
import DoneIcon from "@mui/icons-material/Done";
import Link from "next/link";
const AppBottomNavigation = () => {
const [value, setValue] = useState("dashboard");
const handleChange = (
event: SyntheticEvent,
newValue: string
) => {
setValue(newValue);
};
return (
<Paper
sx={{
position: "fixed",
bottom: 0,
left: 0,
right: 0,
}}
>
<BottomNavigation
value={value}
onChange={handleChange}
>
<BottomNavigationAction
LinkComponent={Link}
href={"/dashboard"}
label={"Home"}
value={"dashboard"}
icon={<HomeIcon />}
/>
<BottomNavigationAction
LinkComponent={Link}
href={"/done"}
label={"Done"}
value={"done"}
icon={<DoneIcon />}
/>
</BottomNavigation>
</Paper>
);
};
export default AppBottomNavigation;
一応 MUI の Issue で報告しておいたので、今後の行く末を見守ろうと思う
この属性自体は ButtonBase で定義されている。デフォルトは <a> タグなので、Link を指定しても問題なかったんだろう。
/**
* The component used to render a link when the `href` prop is provided.
* @default 'a'
*/
LinkComponent?: React.ElementType;
状況
前提として、 Next.js はナビゲーションの遷移に useRouter のフック router.push ではなく <Link> を使用することを推奨している
ただ MUI の BottomNavigation および BottomNavigationAction では component 属性が用意されておらず、Next.js Link コンポーネントを指定できない辛さがあった。ちなみに BottomNavigationAction の直上に Link タグで包むとスタイルが崩れる。
MUI の Issues では Next.js 非推奨の onClick (ブラウザ上で JS 実行) のルーティング例が散見しており、これはSEOに弱いという指摘も同じように見られる。
同様の Issue が私が見かけた限りで4件はあり、全て Link と BottomNavigationAction を使った具体的な例がほしいという内容だったが、「ドキュメント見てね」という内容やちょっとズレたドキュメントの変更で、個人的にはやきもきした
そんな中ようやく見つかった私の報告コメントの直上にある例がこちら
import {BottomNavigation, BottomNavigationAction, Paper} from '@mui/material';
import SupportAgentIcon from '@mui/icons-material/SupportAgent';
import ViewListIcon from '@mui/icons-material/ViewList';
import {NextLinkComposed} from '@/components/Link';
export default function BottomBar() {
return (
<Paper sx={{position: 'fixed', bottom: 0, left: 0, right: 0}} elevation={3}>
<BottomNavigation
showLabels
>
<BottomNavigationAction component={NextLinkComposed} to={{pathname: '/services'}} label="Services" icon={<SupportAgentIcon/>}/>
<BottomNavigationAction component={NextLinkComposed} to={{pathname: '/requests'}} label="My Requests" icon={<ViewListIcon/>}/>
</BottomNavigation>
</Paper>
);
}
https://github.com/mui/material-ui/issues/26655#issuecomment-1466677495
この部分だけ見たら短いように見えるが、よく見ると '@/components/Link' からインポートしている Link.tsx が結構頑張っているコンポーネントとなっている。
しかも <Link> コンポーネントは MUI にも Next.js にも存在しているので、これ以上自前のものを増やしたくない。今後の管理もしたくない。
という感じで型定義を追っていたら LinkComponent に行き着いた。以下のPRとIssueで追加された属性らしい
まあ使えるものは使おうぜということで。