🖇️

Remix の Link で Chakra UI を使いたい

2022/05/31に公開
2

追記

コメントで Chakra Link の as を使えばいいと教えてもらいました🙏
https://chakra-ui.com/docs/components/navigation/link#usage-with-routing-library

link.tsx
import { Link as ChakraLink } from '@chakra-ui/react'
import { Link as RemixLink } from '@remix-run/react'
import type { LinkProps as ChakraLinkProps } from '@chakra-ui/react'
import type { LinkProps as RemixLinkProps } from '@remix-run/react'

export const Link = (
  props: Omit<RemixLinkProps, 'color'> & ChakraLinkProps
) => <ChakraLink as={RemixLink} {...props} />

こんな Link Component を作っておけば、Remix の Link を使いつつ Chakra の props を渡せるようになります。

追記終わり


Remix で a タグのページ内遷移リンクを設置するためには、クライアントサイドルーティングのパフォーマンスを得るために <Link> コンポーネントを使う必要があります。しかしこれ自体がコンポーネントのため、コンポーネントライブラリの Chakra UI との相性が良くありません。

とはいえこれを諦めて style をあてるのは避けたいです。Remix(react-router v6)は useNavigate でページ遷移をすることができますので、onClick をハンドリングするカスタムコンポーネントを作ることで対策する事ができます。

link.tsx
import { forwardRef, Link as ChakraLink } from '@chakra-ui/react'
import { useNavigate } from '@remix-run/react'
import type { LinkProps as ChakraLinkProps } from '@chakra-ui/react'

export const Link = forwardRef<ChakraLinkProps, 'a'>((props, ref) => {
  const navigate = useNavigate()
  const { href } = props

  if (!href) {
    return <ChakraLink ref={ref} {...props} />
  }

  const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
    props.onClick?.(e)
    e.preventDefault()
    navigate(href)
  }

  return <ChakraLink ref={ref} {...props} onClick={handleClick} />
})

使い方は @chakra-ui/react<Link> と同じ

page.tsx
import { Link } from '../components/link'

export default function Page() {
  return <Link bg="blue" href="/page2">aaa</Link>
}

className ベースの tailwindcss ではこういう苦労なさそうですね。なんかもっといい方法あったら教えて下さい。

Next.js の場合

同じく <Link> コンポーネントを使う Next.js では、passHref を追加することによって、aタグのカスタムコンポーネントを利用できることが知られています。
https://nextjs-ja-translation-docs.vercel.app/docs/api-reference/next/link#子が-a-タグをラップするカスタムコンポーネントの場合

Discussion

j5j5

Chakra UIのドキュメントで as prop を使う方法が紹介されていますよー
Link - Chakra UI

9m9m

見落としていました!ありがとうございます!これが一番いいですね
as props を使う方法を追記しました。