見出し画像

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;

https://github.com/mui/material-ui/blob/5bedd502e3f511f964a5ab1baa331fe7f9cacbf0/packages/mui-material/src/ButtonBase/ButtonBase.d.ts#L61-L65


状況

前提として、 Next.js はナビゲーションの遷移に useRouter のフック router.push ではなく <Link> を使用することを推奨している

Recommendation: Use the <Link> component to navigate between routes unless you have a specific requirement for using useRouter.


ただ 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 が結構頑張っているコンポーネントとなっている。

https://github.com/mui/material-ui/blob/da60165a446928263ce33da581ff5d89d3c54d8c/examples/material-next-ts/src/Link.tsx


しかも <Link> コンポーネントは MUI にも Next.js にも存在しているので、これ以上自前のものを増やしたくない。今後の管理もしたくない。


という感じで型定義を追っていたら LinkComponent に行き着いた。以下のPRとIssueで追加された属性らしい


まあ使えるものは使おうぜということで。


この記事が気に入ったらサポートをしてみませんか?