Next.js の Link に Chakra UI の Link や Button のデザインを適応させる方法の Tips
環境
- Next.js
13.2.4- Reat
18.2.0
- Reat
- @chakra-ui/react
2.5.3 - TypeScript
5.0.2
結論: Next.js v13 で Chakra UI を使う場合 Link は @chakra-ui/next-js を使う、リンクボタンは as={NextLink} にする
Link
cf. Getting Started with Next.js - Chakra UI
$ npm i @chakra-ui/next-js
Link
import { Link } from '@chakra-ui/next-js'; export default Page(): JSX.Element { return ( <Link href="/page">Link Text</Link> ); }
Link Button
Chakra UI の as に NextLink を渡せばOK
import NextLink from 'next/link'; import { Button } from '@chakra-ui/react'; export default Page(): JSX.Element { return ( <Button as={NextLink}>Button Label</Button> ); }
Next.js の Link コンポーネント
Next.js では SPA的なページ遷移をするには Next が用意している Link コンポーネントを使う必要があります
Next の Link コンポーネントは <a> タグを出力するので同様に <a> タグや <button> タグを出力するコンポーネントを使用する時は passHref を使うよう書かれています
If the child is a custom component that wraps an <a> tag - Next.js
If the child of Link is a custom component that wraps an
<a>tag, you must addpassHreftoLink. This is necessary if you’re using libraries like styled-components. Without this, the<a>tag will not have thehrefattribute, which hurts your site's accessibility and might affect SEO. If you're using ESLint, there is a built-in rulenext/link-passhrefto ensure correct usage ofpassHref.
import Link from 'next/link' import styled from 'styled-components' // This creates a custom component that wraps an <a> tag const RedLink = styled.a` color: red; ` function NavLink({ href, name }) { return ( <Link href={href} passHref legacyBehavior> <RedLink>{name}</RedLink> </Link> ) } export default NavLink
If the child is a functional component
If the child of
Linkis a functional component, in addition to usingpassHrefandlegacyBehavior, you must wrap the component inReact.forwardRef:
import Link from 'next/link' // `onClick`, `href`, and `ref` need to be passed to the DOM element // for proper handling const MyButton = React.forwardRef(({ onClick, href }, ref) => { return ( <a href={href} onClick={onClick} ref={ref}> Click Me </a> ) }) function Home() { return ( <Link href="/about" passHref legacyBehavior> <MyButton /> </Link> ) } export default Home
Next.js v13 では Chakra UI のコンポーネントを使った時に passHref で入れ子にすると Hydration failed エラーが発生する問題
Next.js v13 ではドキュメントの例に習い Chakra UI の <Link>, <Button> コンポーネントを使おうとすると、リロード時に <a> タグが入れ子になっているという理由で Hydration failed エラーが発生してしまうようです
import NextLink from 'next/link'; import { Link } from '@chakra-ui/react'; export default Page(): JSX.Element { return ( <NextLink href='/page' passHref> <Link>Link Text</Link> </NextLink> ); }
=> Error: Hydration failed because the initial UI does not match what was rendered on the server. Warning: Expected server HTML to contain a matching <a> in <a>.
Button も as="a" で a タグ扱いにすると同様のエラーが発生する
Button のデザインを使いたいリンクを作成したい時にありがちなパターンも passHref で入れ子にすると Hydration failed エラーが発生する
import NextLink from 'next/link'; import { Button } from '@chakra-ui/react'; export default Page(): JSX.Element { return ( <NextLink href='/page' passHref> <Button as="a">Link Text</Button> </NextLink> ); }
=> Error: Hydration failed because the initial UI does not match what was rendered on the server. Warning: Expected server HTML to contain a matching <a> in <a>.
Next.js v13 で Chakra UI の Link, Buttton を使う方法
Link: @chakra-ui/next-js を使う
cf. Getting Started with Next.js - Chakra UI
$ npm i @chakra-ui/next-js
- import NextLink from 'next/link'; - import { Link } from '@chakra-ui/react'; + import { Link } from '@chakra-ui/next-js' export default Page(): JSX.Element { return ( - <NextLink href='/page' passHref> - <Link>Link Text</Link> - </NextLink> + <Link href="/page">Link Text</Link> ); }
Button: as={NextLink} を使う
passHref を使うのではなく Chakra UI の as に NextLink を指定すれば NextLink な ボタンになる
import NextLink from 'next/link';
import { Button } from '@chakra-ui/react';
export default Page(): JSX.Element {
return (
- <NextLink href='/page' passHref>
- <Button as="a">Link Text</Button>
- </NextLink>
+ <Button as={NextLink}>Link Text</Button>
);
}
所感
Next.js と Chakra UI を使ってサクッとサンプルを作りたかっただけなのですが、思いもしない箇所でハマってしまいました。
Hydration failed のエラーについては理解が浅かったのでまた別途調べておきたいと思いました。
おわり
[参考]


