Open9
React Router
なんか難しそうだし、Spring使えばこのあたりは簡単なのではないかと思う。SpringとReact、どちらも使うための環境構築が必要か。
あほめ、Reactの方が簡単じゃないか(4日後のぼくより
恐ろしいほど簡単にページ遷移できるな
App.js
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";
import React from "react";
import { Home } from "./Home";
import { Page1 } from "./Page1";
import { Page2 } from "./Page2";
export const App = () => {
return (
// ルーティングするページは全てBrowserRouterタグで囲む
<BrowserRouter>
{/* リンクを表すにはLinkタグ、URLはtoで指定 */}
<div>
<Link to="/">Home</Link>
<br />
<Link to="/page1">Page1</Link>
<br />
<Link to="/page2">Page2</Link>
</div>
<Switch>
{/* 指定されたページ遷移はRouteタグで行う */}
{/* 完全一致のためにexactを付与する */}
<Route exact path="/">
<Home />
</Route>
<Route path="/page1">
<Page1 />
</Route>
<Route path="/page2">
<Page2 />
</Route>
</Switch>
</BrowserRouter>
);
};
Routeタグでrender関数がpropsで受け取るものの中身
{history: Object, location: Object, match: Object, staticContext: undefined}
history: Object
length: 1
action: "POP"
location: Object
createHref: ƒ createHref() {}
push: ƒ push() {}
replace: ƒ replace() {}
go: ƒ go() {}
goBack: ƒ goBack() {}
goForward: ƒ goForward() {}
block: ƒ block() {}
listen: ƒ listen() {}
location: Object
pathname: "/page1/detailA"
search: ""
hash: ""
state: undefined
match: Object
path: "/page1"
url: "/page1"
isExact: false
params: Object
staticContext: undefined
App.js
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";
import React from "react";
import { Home } from "./Home";
import { Page1 } from "./Page1";
import { Page2 } from "./Page2";
import { Page1DetailA } from "./Page1DetailA";
import { Page1DetailB } from "./Page1DetailB";
export const App = () => {
return (
// ルーティングするページは全てBrowserRouterタグで囲む
<BrowserRouter>
{/* リンクを表すにはLinkタグ、URLはtoで指定 */}
<div>
<Link to="/">Home</Link>
<br />
<Link to="/page1">Page1</Link>
<br />
<Link to="/page2">Page2</Link>
</div>
<Switch>
{/* 指定されたページ遷移はRouteタグで行う */}
{/* 完全一致のためにexactを付与する */}
<Route exact path="/">
<Home />
</Route>
<Route
path="/page1"
{/* propsからmatchのurlを取り出す */}
render={({ match: { url } }) => (
<Switch>
<Route exact path={url}>
<Page1 />
</Route>
{/* urlを"/page1"に確定する */}
<Route path={`${url}/detailA`}>
<Page1DetailA />
</Route>
<Route path={`${url}/detailB`}>
<Page1DetailB />
</Route>
</Switch>
)}
/>
<Route path="/page2">
<Page2 />
</Route>
</Switch>
</BrowserRouter>
);
};
Routerの切り出し
Router.jsx
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";
import { Home } from "../Home";
import { Page1 } from "../Page1";
import { Page2 } from "../Page2";
import { Page1DetailA } from "../Page1DetailA";
import { Page1DetailB } from "../Page1DetailB";
import { page1Routes } from "./Page1Routes";
export const Router = () => {
return (
<Switch>
{/* 指定されたページ遷移はRouteタグで行う */}
{/* 完全一致のためにexactを付与する */}
<Route exact path="/">
<Home />
</Route>
<Route
path="/page1"
render={({ match: { url } }) => (
// switch文の中で、配列を呼び出しループする
<Switch>
{/*
before:
<Route exact path={url}>
<Page1 />
</Route>
<Route path={`${url}/detailA`}>
<Page1DetailA />
</Route>
<Route path={`${url}/detailB`}>
<Page1DetailB />
</Route>
*/}
{/* map関数でpage1Routes配列を一つ取り出し、
route変数に渡す */}
{/* keyはどの要素が変更、追加もしくは削除されたのかを
React が識別するのに役立つ */}
{page1Routes.map((route) => (
<Route
key={route.path}
exact={route.exact}
path={`${url}${route.path}`}
>
{route.children}
</Route>
))}
</Switch>
)}
/>
<Route path="/page2">
<Page2 />
</Route>
</Switch>
);
};
Page1Routes.jsx
import { Page1 } from "../Page1";
import { Page1DetailA } from "../Page1DetailA";
import { Page1DetailB } from "../Page1DetailB";
export const page1Routes = [
{
path: "/",
exact: true,
children: <Page1 />
},
{
path: "/detailA",
exact: false,
children: <Page1DetailA />
},
{
path: "/detailB",
exact: false,
children: <Page1DetailB />
}
];
URLパラメータとクエリパラメータの取得
Page2.jsx
import { Link } from "react-router-dom";
export const Page2 = () => {
return (
<div>
<h1>Page2です</h1>
{/* URLパラメータ100を取得して表示 */}
<Link to="/page2/100">URL Parameter</Link>
<br />
{/* クエリパラメータhogehogeを取得して表示 */}
<Link to="/page2/100?name=hogehoge">Query Parameter</Link>
</div>
);
};
Page2Routes.jsx
import { Page2 } from "../Page2";
import { UrlParameter } from "../UrlParameter";
export const page2Routes = [
{
path: "/",
exact: true,
children: <Page2 />
},
{
// urlの後ろ(/page2/~)の数値をidに格納
path: "/:id",
exact: false,
children: <UrlParameter />
}
];
UrlParameter.jsx
import { useParams, useLocation } from "react-router-dom";
export const UrlParameter = () => {
// /:idで指定されている値を取得する
const { id } = useParams();
// 様々なパラメータ情報を取得する
const { search } = useLocation();
// クエリパラメータを簡単に扱える
const query = new URLSearchParams(search);
return (
<div>
<h1>UrlParameterです</h1>
<p>パラメータは {id} です</p>
{/* クエリパラメータの取得
~?name=hogehogeからhogehogeを取得する */}
<p>パラメータは {query.get("name")} です</p>
</div>
);
};
URLSearchParamsクラスについて
useLocation()の中身
{pathname: "/page2/100", search: "?name=hogehoge", hash: "", state: undefined}
pathname: "/page2/100"
search: "?name=hogehoge"
hash: ""
state: undefined
ページ間で値を渡す際には<Link>を使用する
ページ遷移をする場合は、useHistoryを使用することが多い
Page1.jsx
import { Link, useHistory } from "react-router-dom";
export const Page1 = () => {
// 1から100までの無意味な配列
const arr = [...Array(100).keys()];
// ページ遷移はuseHistoryを使う
const history = useHistory();
const onClickDetailA = () => history.push("/page1/detailA");
return (
<div>
<h1>Page1です</h1>
{/* pathの正確な書き方 */}
{/* stateに値arrを設定してpathnameに渡す */}
<Link to={{ pathname: "/page1/detailA", state: arr }}>DetailA</Link>
<br />
<Link to="/page1/detailA">DetailB</Link>
<br />
<button onClick={onClickDetailA}>DetailA</button>
</div>
);
};
Page1DetailA.jsx
import { useHistory, useLocation } from "react-router-dom";
export const Page1DetailA = () => {
// useLocationのstateにより受け取る
const { state } = useLocation();
//ブラウザの遷移はuseHistoryを使う
const history = useHistory();
// ブラウザの戻る機能のようなもの
const onClickBack = () => history.goBack();
return (
<div>
<h1>Page1DetailAです</h1>
<button onClick={onClickBack}>戻る</button>
</div>
);
};
useLocationの中身
{pathname: "/page1/detailA", state: Array(100), search: "", hash: "", key: "w3y4sc"}
pathname: "/page1/detailA"
state: Array(100)
search: ""
hash: ""
key: "w3y4sc"
** 404ページについて
以下のようにRouteの最後につける。アスタリスクでその他を表す
Router.tsx
<Route
path="/home"
render={({ match: { url } }) => (
<Switch>
{homeRoutes.map((route) => (
<Route
key={route.path}
exact={route.exact}
path={`${url}${route.path}`}
>
{route.children}
</Route>
))}
</Switch>
)}
/>
<Route path="*">
<Page404 />
</Route>
また、/home/xxxxのように階層が異なる場合にも適用できるようにするには、Routesに追加していく
HomeRoutes.tsx
export const homeRoutes = [
{
path: "/",
exact: true,
children: <Home />
},
{
path: "/user_management",
exact: false,
children: <UserManagement />
},
{
path: "/setting",
exact: false,
children: <Setting />
},
{
path: "*",
exact: false,
children: <Page404 />
}
];
ver18での変更
switchタグが無くなって、Routesタグになった
確かにSwitchってよくわからんかった
App18.jsx
const App = () => {
return (
<BrowserRouter>
<Routes> //ここが変わったかな
<Route path={`/`} element={<Home />} />
<Route path={`/page1/`} element={<Page1 />} />
<Route path={`/page2/`} element={<Page2 />} />
</Routes>
</BrowserRouter>
);
};