React RouterやTanStackを使わないページ移動の実装方法(File-based routing)
2026.3.10
この記事は約2分で読めます
Next.jsのような『ファイルがそのままページに対応する仕組み』を、パッケージに頼らず実装してみましょう。
意外とシンプルに実現できます。

筆者:三好アキ
▶︎ 三好アキの著書一覧はこちら
パッケージなしでページを遷移(ファイルでページを設定)
React(+ Vite)アプリでページ切り替え(ルーティング)を実装する時には、React RouterやTanStack Routerを使うのが一般的です。
しかしこれらを使わずともルーティングは可能なので、その簡単な方法を紹介します。
本記事では、Next.jsのような『ファイルがページに対応している切り替え(File-based routing)』を説明します。
コードでページを切り替える方式(Code-based routing)については、こちらの記事をご覧ください。
まずはReact + Viteを用意しましょう。
そしてindex.css内のコードはすべて消しておいてください。
(*React + Viteのセットアップについてはこちらの記事をご覧ください)
ページの用意
ページとして使うファイルを入れるpagesフォルダを用意します。
次のようにファイルを用意してください。
各ファイルには次のように書きます。
// pages/home.jsx
const Home = () => {
return (
<div>
<h1>Home</h1>
</div>
)
}
export default Home// pages/about.jsx
const About = () => {
return (
<div>
<h1>About</h1>
</div>
)
}
export default About// pages/notfound.jsx
const NotFound = () => {
return (
<div>
<h1>Not Found</h1>
</div>
)
}
export default NotFoundページ切り替えの仕組みの用意
まずApp.jsxのコードをすべて消して、次のように書いてください。
// App.jsx
const App = () => {
return
}
export default Appそして先ほど作ったファイルをすべて読み込みます。
// App.jsx
const pages = import.meta.glob("./pages/**/*.jsx", { eager: true }) // 追加
const App = () => {
return
}
export default App参考ですが、このpagesの中身は次のようになっています。
次はファイルパスをURLに変換します。
// App.jsx
const pages = import.meta.glob("./pages/**/*.jsx", { eager: true })
// ⬇追加
function normalizePath(filePath) {
return filePath
.replace("./pages", "")
.replace("/home.jsx", "")
.replace(".jsx", "") || "/"
}
// ⬆追加
const App = () => {
return
}
export default App最後に、これらを使ってルーティングを実現するコードを追加しましょう。
// App.jsx
import { useEffect, useState } from "react" // 追加
const pages = import.meta.glob("./pages/**/*.jsx", { eager: true })
function normalizePath(filePath) {
return filePath
.replace("./pages", "")
.replace("/home.jsx", "")
.replace(".jsx", "") || "/"
}
const App = () => {
// ⬇追加
const [path, setPath] = useState(window.location.pathname)
useEffect(() => {
const onPopState = () => setPath(window.location.pathname)
window.addEventListener("popstate", onPopState)
return () => window.removeEventListener("popstate", onPopState)
}, [])
const Page = Object.entries(pages).find(
([file]) => normalizePath(file) === path
)?.[1].default
return Page ? <Page/> : <h1>エラー</h1>
// ⬆追加
}
export default AppLinkタグの用意
ページを移動するリンクに<a>タグを使い、次のように書くとします。
<a href="/about">About</a>しかしこれではページがリロードされてしまい、SPA(Single Page Application)の特徴である「スムーズなページ遷移」にはなりません。
なので専用の<Link>タグを用意しましょう。
Link.jsxを作ってください。
次のように書きます。
// Link.jsx
export function Link({ to, children }) {
const handleClick = (e) => {
e.preventDefault()
window.history.pushState({}, "", to)
window.dispatchEvent(new PopStateEvent("popstate"))
}
return (
<a href={to} onClick={handleClick}>
{children}
</a>
)
}
export default Linkそして各ページに読み込みましょう。
// pages/home.jsx
import Link from "../Link" // 追加
const Home = () => {
return (
<div>
<h1>Home</h1>
<Link to="/about">About</Link> // 追加
</div>
)
}
export default Home// pages/about.jsx
import Link from "../Link" // 追加
const About = () => {
return (
<div>
<h1>About</h1>
<Link to="/home">Home</Link> // 追加
</div>
)
}
export default About// pages/notfound.jsx
import Link from "../Link" // 追加
const NotFound = () => {
return (
<div>
<h1>Not Found</h1>
<Link to="/home">Home</Link> // 追加
</div>
)
}
export default NotFoundこれで、パッケージを使わない、ファイルベースでのルーティングをReactに実装できました。
しかしこのようなマニュアル方式には限界もあります。
この実装方法の限界
ページが増えたときにコードも増えていく、動的ルートが扱いづらい、テストが書きづらいといった問題が典型的です。
そのためやはり一般的には、React RouterやTanStack Routerといったパッケージを使うことになります。
なお、もうひとつの切り替え方式である『コードでページを切り替える方法(Code-based routing)』については、こちらの記事をご覧ください。
▼【無料フロントエンド・ガイド】は下記ページで受け取れます。

🟩 フロントエンド開発者入門ガイド【無料配布中】
最初にこれが知りたかった!
フロントエンド初心者が必ず押さえておきたい ― 『挫折しない勉強法』とその具体的ステップ、無料配布中。
(*名前不要・メールアドレスだけで受け取り可能です)


