Next.js + Material UIで文字とアイコンによるリンクを作成
概要
Next.jsには備えつけのLinkコンポーネントがあります。
個人開発をしていて、「アイコンと文字がchildとしてどっちもあるリンクを作ろう!」と思い、Next.jsのLinkにてそれをしようと思ったのですが、エラーを吐かれてしまい困りました。
どんなエラー?
こんなエラーです。
Error: Multiple children were passed to <Link> with `href` of `/` but only one child is supported https://nextjs.org/docs/messages/link-multiple-children
かいつまむと、「複数のchildがLinkに渡されているが、サポートされているchildの数は1つだよ」と言われているようです。
その時点ではこのようにして書いていました。
CreateはMaterial UIの鉛筆アイコンです。
import Link from "next/link"
import { Create } from "@mui/icons-material"
<Link href="/">
<a>記事を書く</a>
<Create />
</Link>
「記事を書く」というaタグと、鉛筆アイコンは別のものなのだから、どうやってもchildは2つになるのでは?と思い困っていました。
解決策
ただ調べていると、以下のようにするとやりたいことが実現できるのがわかりました。
import MuiLink from "@mui/material/Link"
import NextLink from "next/link"
<NextLink href="/edit" passHref>
<MuiLink
underline="none"
css={css`
color: black;
text-decoration: none;
display: flex;
align-items: center;
`}
>
記事を書く
<Create />
</MuiLink>
</NextLink>
かんたんに解説します。
LinkコンポーネントはNext.jsとMaterial UIのどちらともからimportしてきて、それぞれNextLink, MuiLinkと名付けます。
使用の際はNextLinkでMuiLinkをラップして、NextLinkのhrefで遷移先を指定、およびpassHrefをセットして、MuiLinkに遷移先のデータを渡してあげます。
イメージとしては、普段Next.jsでLinkを使う際にchildとして入れているaタグがMuiLinkになった感じです。
NextLinkはMuiLinkという一つのchildしか持っていないため、ちゃんと条件を満たしており、かつMuiLinkでは複数のchildを持つことが許容されているので、この形によってやりたいことが実現できるというわけです。
ちなみに実際のページ遷移の処理はNext.js側のLinkが作動しています。
また、生の状態だと文字とアイコンの高さの配置がずれてしまうので、文字色などと併せてcssで整えています。
完成形の見た目は以下になります。
やったね!
ちなみに
私はNext.js初心者なので、「Material UIのLinkは複数のchildを許容してくれるなら、初めからそっちだけ使えばいいのでは?」と少し悪いことを考えたりもしました。
しかし結論を言うと、そうするとNext.js特有の、クライアントサイドでのページ遷移が使えなくなるので、本来なら出せたスピードを出すことができず、結果的にサイトのパフォーマンスを部分的に下げる可能性があります。
実際にMaterial UIのLinkとNext.jsのLinkの遷移速度を比べてみたところ、遷移先が軽いページだとあまり速さは変わりませんでしたが、重いコンポーネントを持ったページだと結構な時間ちがいました。
なので、Next.js環境でLink内で文字とアイコンを併存させたいときは、この方法をおすすめします👌
(そもそもNext.jsを使っている以上、Routingや遷移などで備えつけのコンポーネントを使わないのは、おそらくナンセンスなのでしょう)
参考記事
Discussion