next/linkとreact-router-domの違いを調べてみた
Next.jsの場合は、next/link
、React(Next.jsを使用しない)の場合はreact-router-dom
を特に何も考えず使用していたため、違いなどについてまとめていこうと思います。
next/link
とは
Next.js has a file-system based router built on the concept of pages.
When a file is added to the pages directory, it's automatically available as a route.
The files inside the pages directory can be used to define most common patterns.
The Next.js router allows you to do client-side route transitions between pages, similar to a single-page application.
A React component called Link is provided to do this client-side route transition.
Next.js側でファイルシステムルータシステムがあり、シングルページのアプリケーションと同様にページ間のクライアントサイドのルート遷移を行うためのコンポーネント。
基本的な使い方
以下のページに対してルーティングを行う場合
- pages/index.js
- pages/about.js
- pages/blog/[slug].js
function Home() {
return (
<ul>
<li>
<Link href="/">Home</Link>
</li>
<li>
<Link href="/about">About Us</Link>
</li>
<li>
<Link href="/blog/hello-world">Blog Post</Link>
</li>
</ul>
)
}
型の情報について
検証したバージョンは13.0.3
です。
declare type InternalLinkProps = {
href: Url;
as?: Url;
replace?: boolean;
scroll?: boolean;
shallow?: boolean;
passHref?: boolean;
prefetch?: boolean;
locale?: string | false;
legacyBehavior?: boolean;
onMouseEnter?: (e: any) => void;
onTouchStart?: (e: any) => void;
onClick?: (e: any) => void;
};
export declare type LinkProps = InternalLinkProps;
declare const Link: React.<Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof InternalLinkProps> & InternalLinkProps & {
children?: React.ReactNode;
} & React.RefAttributes<HTMLAnchorElement>>;
react-router-dom
とは
In traditional websites, the browser requests a document from a web server, downloads and evaluates CSS and JavaScript assets, and renders the HTML sent from the server. When the user clicks a link, it starts the process all over again for a new page.
Client side routing allows your app to update the URL from a link click without making another request for another document from the server. Instead, your app can immediately render some new UI and make data requests with fetch to update the page with new information.
This enables faster user experiences because the browser doesn't need to request an entirely new document or re-evaluate CSS and JavaScript assets for the next page. It also enables more dynamic user experiences with things like animation.
クライアントサイドルーティングを可能にする仕組み。
ページ遷移する場合、通常のWebサイトではページを読み込むたびにCSS,JavaScriptのアセットをダウントーろして評価したり、サーバーから送られてきたHTMLをレンダリングしている。
クライアントサイドルーティングを使用すると、サーバーから別のドキュメントを再度要求することなく、リンククリックによるURLの更新を行うことサーバーから別のドキュメントを再度要求することなく、リンククリックによるURLの更新を行うことができる。
そのため、通常のWebブラウザでの遷移よりクライアントサイドルーティングを使用することで高速にページ遷移を行うことができる。
基本的な使い方
const router = createBrowserRouter([
{
path: "/",
element: (
<div>
<h1>Hello World</h1>
<Link to="about">About Us</Link>
</div>
),
},
{
path: "about",
element: <div>About</div>,
},
]);
createRoot(document.getElementById("root")).render(
<RouterProvider router={router} />
);
型の情報について
検証したバージョンは6.4.3
です。
declare function Link(props: LinkProps): React.ReactElement;
interface LinkProps
extends Omit<
React.AnchorHTMLAttributes<HTMLAnchorElement>,
"href"
> {
replace?: boolean;
state?: any;
to: To;
reloadDocument?: boolean;
}
type To = string | Partial<Path>;
next/link
とreact-router-dom
の違いについて
Next.jsを使用する場合、react-router-dom
ではなく、next/link
を使用した方がよい理由について
- Decrease bundle size by removing React Router as a dependency.
- Define your application routes through the file system.
- Utilize the latest improvements to the Next.js framework.Utilize the latest improvements to the Next.js framework.
バンドルサイズを削減することができ、ファイルシステムを利用してルートの定義を設定することができる。
react-router-dom
でアプリケーション構造を設定したい場合
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
export default function App() {
return (
<Router>
<Switch>
<Route path="/about">
<h1>About</h1>
</Route>
<Route path="/blog">
<h1>Blog</h1>
</Route>
<Route path="/">
<h1>Home</h1>
</Route>
</Switch>
</Router>
)
}
Next.jsでアプリケーション構造を設定したい場合
以下のディレクトリを作成するのみ
-
pages/about.js
→/about
-
pages/blog.js
→/blog
-
pages/index.js
→/
動的なパスを設定したい場合
react-router-dom
の場合
import {
BrowserRouter as Router,
Switch,
Route,
useRouteMatch,
useParams,
} from 'react-router-dom'
export default function Blog() {
// Nested route under /blog
const match = useRouteMatch()
return (
<Router>
<Switch>
<Route path={`${match.path}/:slug`}>
<Post />
</Route>
<Route path={match.path}>
<h1>All Blog Posts</h1>
</Route>
</Switch>
</Router>
)
}
function Post() {
const { slug } = useParams()
return <h1>Post Slug: {slug}</h1>
}
Next.jsの場合
// pages/blog/index.js
export default function Blog() {
return <h1>All Blog Posts</h1>
}
// pages/blog/[slug].js
import { useRouter } from 'next/router'
export default function Post() {
const router = useRouter()
const { slug } = router.query
return <h1>Post Slug: {slug}</h1>
}
違いについて
-
react-router-dom
では、そもそものルーティング機能・ページ遷移まで全てを提供している。使用する場合、ルート部分でルーティングの設定の必要あり。 -
next/link
では、ルーティング機能はNext.js
が提供しており、ページ遷移のコンポーネントを提供している。
各種UIライブラリでのLinkコンポーネントの実装について
ルーティングの違いについて、上記のとおりだが、各種コンポーネントライブラリがどのように実装されているのか
chakra uiの場合
react-router-dom
の場合、as
を送るのみで良い。
// 1. import { Link as ReachLink } from "@reach/router"
// 2. Then use it like this
<Link as={ReachLink} to='/home'>
Home
</Link>
next/link
の場合、next/link
で囲む必要あり
// 1. import NextLink from "next/link"
// 2. Then use it like this
<NextLink href='/home' passHref>
<Link>Home</Link>
</NextLink>
Next.jsのバージョンが13以上の場合は、以下にする必要あり
パターン1: legacyBehavior
とpassHref
をpropsに入れる
import NextLink from 'next/link'
import { Link, Heading } from '@chakra-ui/react'
...
<NextLink href='...' legacyBehavior passHref>
<Link>
<Heading>...</Heading>
</Link>
</NextLink>
パターン2: カスタムコンポーネントの作成
import NextLink, { type LinkProps as NextLinkProps } from 'next/link'
import { chakra } from '@chakra-ui/react'
// wrap the NextLink with Chakra UI's factory function
const MagicLink = chakra<typeof NextLink, NextLinkProps>(NextLink, {
// ensure that you're forwarding all of the required props for your case
shouldForwardProp: (prop) => ['href', 'target', 'children', ...].includes(prop),
})
// use the MagicLink just like you'd use the ordinary Chakra UI link
<MagicLink
href='...'
color='...'
target='...'
>
...
</MagicLink>
Material UIの場合
react-router-dom
の場合、Link
コンポーネントにcomponent
を送るのみか、カスタムコンポーネントを作成し、それをpropsに送る。
パターン1: Link
コンポーネントにcomponent
を送る
import {
Link as RouterLink,
} from 'react-router-dom';
import Link from '@mui/material/Link';
<Link component={RouterLink} to="/">
With prop forwarding
</Link>
パターン2: カスタムコンポーネントを作成し、それをpropsに送る
import {
Link as RouterLink,
LinkProps as RouterLinkProps,
} from 'react-router-dom';
const LinkBehavior = React.forwardRef<any, Omit<RouterLinkProps, 'to'>>(
(props, ref) => (
<RouterLink
ref={ref}
to="/material-ui/getting-started/installation/"
{...props}
/>
),
);
<Link component={LinkBehavior}>Without prop forwarding</Link>
Next.jsの場合、以下のナビゲーションの処理のみを行うコンポーネントを使用する。
import Button from '@mui/material/Button';
import { NextLinkComposed } from '../src/Link';
export default function Index() {
return (
<Button
component={NextLinkComposed}
to={{
pathname: '/about',
query: { name: 'test' },
}}
>
Button link
</Button>
);
}
また、リンクスタイル付きのものを使用したい場合は以下を使用する。
import Link from '../src/Link';
export default function Index() {
return (
<Link
href={{
pathname: '/about',
query: { name: 'test' },
}}
>
Link
</Link>
);
}
各種ライブラリでの対応について
- 基本コンポーネントをpropsで送ることができるようにしている
- 例外でのパターンは独自でコンポーネントを作ってそれを適応させたり、カスタムコンポーネントを作成したりなどさまざま
Discussion