React でページ遷移の導入として react-router-dom
(v6.16.0) を使ってやってみる
SPAとはいえページがあることで恩恵を受けることも結構あるのでやってみる
package.json に homepage
設定した時にちょっとはまった。。。
process.env.PUBLIC_URL
を使うことで解決したのでそのあたりをメモしてます
ベースとして create-react-app
から作ったプロジェクトから不要ファイル削除したやつを使ってます
やることとしては大雑把にこんな感じ
- Reactプロジェクト作成 Win11
- Reactプロジェクトから不要ファイル削除(./src直下削除)
- Reactプロジェクトでページ遷移(react-router-dom v6.16.0使用)
- react-router-dom インストール
- ページのディレクトリ作成
- ページ遷移の実装
- ページ遷移の実装(コンポーネントにまとめる)
- ページリンクのスタイル調整
あと最終的に出来上がるやつはここにおいてます
https://github.com/sueasen/my-app-react-router-dom
React プロジェクト作成 Win11
こちらのページ参考、Node.jsインストールからやってます
React プロジェクトから不要ファイル削除(./src直下削除)
こちらのページ参考、初期化して index.js
と App.js
に簡単に分けてる感じです
Reactプロジェクトでページ遷移(react-router-dom v6.16.0使用)
react-router-dom インストール
以下のコマンドを実行するだけ
npm i react-router-dom
ページのディレクトリ作成
pages
ディレクトリを src
直下に作成する
ページ遷移の実装
ページ遷移の実装の流れとしては以下のステップを踏む
- 遷移用ページのコンポーネント作成
-
BrowserRouter
よりページ情報定義・表示 - ページ遷移のリンク追加
遷移用ページのコンポーネント作成
pages
直下に簡単に文字を表示するだけのページを3つ(Home
, Page1
, Page2
)作成する
Page2
は props
(引数) もらうようにしておく
const Home = () => {
return (
<>
<p>Home</p>
</>
);
};
export default Home;
const Page1 = () => {
return (
<>
<p>Page1</p>
</>
);
};
export default Page1;
const Page2 = (props) => {
return (
<>
<p>Page2 {props.text}</p>
</>
);
};
export default Page2;
BrowserRouter
よりページ情報定義・表示
App.js に BrowserRouter
使ってページ情報を定義・表示するために以下をやる
- BrowserRouter, Routes, Route を react-router-dom からインポート
- ページ用コンポーネントをインポート
- BrowserRouter の basename に
process.env.PUBLIC_URL
を設定-
process.env.PUBLIC_URL
を設定するとhomepage
設定した時などパスが狂わなくなる
-
- Route に各々の
path
,element
(コンポーネント) を設定
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import Page1 from './pages/Page1';
import Page2 from './pages/Page2';
const App = () => {
return (
<>
<h1>Hello World</h1>
<p>App.jsx</p>
{/* BrowserRouter, Routes, Route の定義、path に一致する element を表示 */}
<BrowserRouter basename={process.env.PUBLIC_URL}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/page1" element={<Page1 />} />
<Route path="/page2" element={<Page2 text="text sample" />} />
</Routes>
</BrowserRouter>
</>
);
};
export default App;
ページ遷移のリンク追加
ページ遷移用のリンクを追加すればOK
設定するリンクには basename に設定した process.env.PUBLIC_URL
を付けるとパスが狂わなくなる
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import Page1 from './pages/Page1';
import Page2 from './pages/Page2';
const App = () => {
return (
<>
<h1>Hello World</h1>
<p>App.jsx</p>
{/* 以下リンクを追加 */}
<ul>
<li>
<a href={`${process.env.PUBLIC_URL}/`}>Home</a>
</li>
<li>
<a href={`${process.env.PUBLIC_URL}/page1`}>Page1</a>
</li>
<li>
<a href={`${process.env.PUBLIC_URL}/page2`}>Page2</a>
</li>
</ul>
{/* BrowserRouter, Routes, Route を定義 */}
<BrowserRouter basename={process.env.PUBLIC_URL}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/page1" element={<Page1 />} />
<Route path="/page2" element={<Page2 text="text sample" />} />
</Routes>
</BrowserRouter>
</>
);
};
export default App;
ページ遷移の実装(コンポーネントにまとめる)
ページ遷移の実装をコンポーネントにまとめてみる
ページ遷移に関する情報を変数定義してそれを渡して BrowserRouter
, ページ遷移リンクを返すやつを作る
もっと良い方法ありそうだが定義したページ情報を渡せばできる形にしてみる
ページ遷移リンクのコンポーネント作成
ページ遷移リンク を返すコンポーネントを pages
直下に AppRouter.js
として作る
import { BrowserRouter, Routes, Route } from 'react-router-dom';
// pages は [{key:key1, path:path1, element:element1}, ...] を受け取る
export const appRouter = (pages) => {
// BrowserRouter 返す処理
const router = () => {
return (
<>
<BrowserRouter basename={process.env.PUBLIC_URL}>
<Routes>
{pages.map((p) => (
<Route key={p.key} path={p.path} element={p.element} />
))}
</Routes>
</BrowserRouter>
</>
);
};
// ページ遷移リンク 返す処理
const links = () => (
<ul>
{pages.map((p) => (
<li key={p.key}>
<a href={`${process.env.PUBLIC_URL}${p.path}`}>{p.key}</a>
</li>
))}
</ul>
);
// BrowserRouter, ページ遷移リンク の定義を返す
return {
browserRouter: router(),
navbarLink: links(),
};
};
App.js から AppRouer.js を使って実装
インポートして pages を定義して AppRouer に設定する
後は browserRouter
, navbarLink
を使って書き換える
import { appRouter } from './pages/AppRouter';
import Home from './pages/Home';
import Page1 from './pages/Page1';
import Page2 from './pages/Page2';
// ページ情報を定義して appRouter に設定
const pages = [
{ key: 'Home', path: '/', element: <Home /> },
{ key: 'Page1', path: '/page1', element: <Page1 /> },
{ key: 'Page2', path: '/page2', element: <Page2 text="text sample" /> },
];
const router = appRouter(pages);
const App = () => {
return (
<>
<h1>Hello World</h1>
<p>App.jsx</p>
{/* appRouter の navbarLink に書き換え*/}
{router.navbarLink}
{/* appRouter の browserRouter に書き換え*/}
{router.browserRouter}
</>
);
};
export default App;
実行してページ遷移が出来ればOK!!
ページリンクのスタイル調整
メニューリンクなどにスタイルをあてる
-
App.css
: 新規作成、スタイルを定義 -
App.js
: インポート追加App.css
-
AppRouter.js
: タグやクラス属性を追加
body {
margin: 0;
font-family: "Futura", Helvetica, sans-serif;
}
/* Navbar & Navmenu color */
:root {
--background-navbar: rgba(55, 55, 55, 0.98);
--height-navbar: 52px;
}
.header {
background: var(--background-navbar);
position: fixed;
width: 100%;
height: var(--height-navbar);
z-index: 3000;
}
/* Nav items */
.menu {
list-style: none;
position: absolute;
width: 100%;
height: auto;
top: 0;
margin-top: var(--height-navbar);
padding: 0 0 10px 0;
clear: both;
background: var(--background-navbar);
transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
transform: scale(1, 0);
transform-origin: top;
}
/* Hamburger menu button */
.menu-btn:checked~.menu {
transform: scale(1, 1);
transform-origin: top;
transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
}
/* Hamburger menbu text */
.menu a {
text-decoration: none;
font-weight: 500;
letter-spacing: 2px;
font-size: 16px;
text-transform: capitalize;
color: #ddd;
opacity: 0;
transition: 0.5s;
}
.menu li {
border-top: 1px solid rgb(75, 75, 75);
padding: 15px 0;
margin: 0 54px;
opacity: 0;
transition: 0.5s;
}
.menu-btn:checked~.menu a,
.menu-btn:checked~.menu li {
opacity: 1;
transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.2s;
}
.menu-btn {
display: none;
}
.menu-icon {
display: inline-block;
position: relative;
cursor: pointer;
padding: 24px 14px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.navicon {
background: #ddd;
display: block;
height: 3px;
width: 26px;
position: relative;
transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
}
.navicon:before,
.navicon:after {
content: "";
display: block;
height: 100%;
width: 100%;
position: absolute;
background: #ddd;
transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
}
.navicon:before {
top: 9px;
}
.navicon:after {
bottom: 9px;
}
/* Hamburger Menu Animation Start */
.menu-btn:checked~.menu-icon .navicon:before {
transform: rotate(-45deg);
}
.menu-btn:checked~.menu-icon .navicon:after {
transform: rotate(45deg);
}
.menu-btn:checked~.menu-icon:not(.steps) .navicon:before {
top: 0;
}
.menu-btn:checked~.menu-icon:not(.steps) .navicon:after {
bottom: 0;
}
.menu-btn:checked~.menu-icon .navicon {
background: rgba(0, 0, 0, 0);
transition: 0.2192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
}
/* Hamburger Menu Animation End */
/* Navbar Container */
.navtext-container {
width: 100%;
height: var(--height-navbar);
position: absolute;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
}
/* Navbar Text */
.navtext {
position: absolute;
text-transform: uppercase;
color: #ddd;
letter-spacing: 4px;
font-size: 20px;
}
main {
padding-top: var(--height-navbar);
}
import { appRouter } from './pages/AppRouter';
import Home from './pages/Home';
import Page1 from './pages/Page1';
import Page2 from './pages/Page2';
// css 追加
import './App.css';
// ページ情報を定義して appRouter に設定
const pages = [
{ key: 'Home', path: '/', element: <Home /> },
{ key: 'Page1', path: '/page1', element: <Page1 /> },
{ key: 'Page2', path: '/page2', element: <Page2 text="text sample" /> },
];
const router = appRouter(pages);
const App = () => {
return (
<>
{router.navbarLink}
{/* 位置調整で main で括る */}
<main>
<h1>Hello World</h1>
<p>App.jsx</p>
{router.browserRouter}
</main>
</>
);
};
export default App;
import { BrowserRouter, Routes, Route } from 'react-router-dom';
export const appRouter = (pages) => {
const router = () => {
return (
<>
<BrowserRouter basename={process.env.PUBLIC_URL}>
<Routes>
{pages.map((p) => (
<Route key={p.key} path={p.path} element={p.element} />
))}
</Routes>
</BrowserRouter>
</>
);
};
// タグ, クラスなど追加
const links = () => (
<header className="header">
<div className="navtext-container">
<div className="navtext">title</div>
</div>
<input type="checkbox" className="menu-btn" id="menu-btn" />
<label htmlFor="menu-btn" className="menu-icon">
<span className="navicon"></span>
</label>
<ul className="menu">
{pages.map((p) => (
<li key={p.key}>
<a href={`${process.env.PUBLIC_URL}${p.path}`}>{p.key}</a>
</li>
))}
</ul>
</header>
);
return {
browserRouter: router(),
navbarLink: links(),
};
};
こんな感じで表示されればOK