公文書
まずreactプロジェクトを作成します。 ここでは、create-react-appを使った簡単な作成方法を紹介します。
npx create-react-app react-router-dom-demo
それからreact-router-domをダウンロードしてインストールしてください。
cd react-router-dom-demo
yarn add react-router-dom
プロジェクトの開始
yarn start
Demo Githubアドレス
BaseRoute -- 基本ルート
import React from "react";
import {
//asの役割は、HashRouterをRouterにリネームすることで、HashRouterとBrowserRouterを何度もテストする際に、コンポーネントの修正が不要になるというメリットがある。
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
</div>
);
}
UrlParameters -- ダイナミック・ルーティング
ルートのパラメータを取得するには、フック :param の形式か、オリジナルの
props.match.params.xxx
<Route></Route>props.match.params.xxx注:タグの子タグに children={} が使用されている場合、primitive メソッドは機能せず、useParams() の方法でのみ使用できます。 Route タグの属性については、後で説明します。
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams
} from "react-router-dom";
export default class UrlParameters extends Component {
render() {
return (
<Router>
<div>
<h2>Accounts</h2>
<ul>
<li>
<Link to="/netflix">Netflix</Link>
</li>
<li>
<Link to="/zillow-group">Zillow Group</Link>
</li>
<li>
<Link to="/yahoo">Yahoo</Link>
</li>
<li>
<Link to="/modus-create">Modus Create</Link>
</li>
</ul>
<Switch>
<Route path="/:id" component={Child} />
</Switch>
</div>
</Router>
)
}
}
function Child(props) {
// We can use the `useParams` hook here to access
// the dynamic pieces of the URL.
let { id } = useParams();
let idd = props.match.params.id;
return (
<div>
<h3>ID: {id} ,other:{idd}</h3>
</div>
);
}
NestingRouter -- ネストされたルート
ネストされたルートは明確な階層があるときに使われます。 これは単にルートの下にサブルートがあることを意味します。
例で使用されている新しいフック:useRouteMatch
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams,
useRouteMatch
} from "react-router-dom";
export default class NestingRouter extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</div>
</Router>
)
}
}
function Home(){
return(
<div>
<h2>Home</h2>
</div>
)
}
function Topics(){
// The `path` lets us build <Route> paths that are
// relative to the parent route, while the `url` lets
// us build relative links.
let { path, url } = useRouteMatch()
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${url}/rendering`}>Rendering with React</Link>
</li>
<li>
<Link to={`${url}/components`}>Components</Link>
</li>
<li>
<Link to={`${url}/props-v-state`}>Props v. State</Link>
</li>
</ul>
<Switch>
<Route exact path={path}>
<h3>Please select a topic.</h3>
</Route>
<Route path={`${path}/:topicId`}>
<Topic />
</Route>
</Switch>
</div>
)
}
function Topic(){
let { topicId } = useParams();
return (
<div>
<h3>{topicId}</h3>
</div>
);
}
トピック・コンポーネントの useRouteMatch を表示します。
結果は以下の通り。
pathとurlの値は同じで、公式の説明では、pathは親ルートからの相対
パスを 作成可能にし、urlは相対リンクを作成可能にします。これを訳すと次のようになります。 urlはLinkコンポーネントへのジャンプに使われます。
RedirectRoute(Auth) -- リダイレクトルート
まず、ページのロジックを分析しましょう。
PublicPage、LoginPage、ProtectedPageの3つのページがあります。
保護されたページを表示するには、ログインする必要があります。
次に、コードを順を追って分析します
AuthButtonコンポーネントは、ログインし直したりしても再レンダリングされないので、変更されることはありません。 PrivateRouteに入れて表示するだけです。
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
useHistory,
useLocation
} from "react-router-dom";
//Redirect は新しい場所にナビゲートし、リダイレクトする。
//useHistory useHistoryフックを使うと、ナビゲーションに使える履歴のインスタンスにアクセスできる。
//useLocationフックは、現在のURLを表すロケーションオブジェクトを返す。これはuseStateと考えることができ、URLが表示されたときに新しいロケーションの変更を返す。これは、例えばウェブ解析を使用して、新しいページがロードされるたびに新しい「ページビュー」イベントをトリガーしたい場合に便利である。
export default class RedirectRouter extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/public">Public Page</Link>
</li>
<li>
<Link to="/protected">Protected Page</Link>
</li>
</ul>
<Switch>
<Route path="/public">
<PublicPage />
</Route>
<Route path="/login">
<LoginPage />
</Route>
<PrivateRoute path="/protected">
<AuthButton />
<ProtectedPage />
</PrivateRoute>
</Switch>
</div>
</Router>
)
}
}
//変数の定義とログアウト
const fakeAuth = {
isAuthenticated: false, //ログインするかどうか
authenticate(cb) { //ログインメソッド
fakeAuth.isAuthenticated = true;
setTimeout(cb, 100); // fake async
},
signout(cb) { //ログアウトメソッド
fakeAuth.isAuthenticated = false;
setTimeout(cb, 100);
}
}
//ログイン・コントロール・ボタン・コンポーネント
function AuthButton() {
let history = useHistory();
return fakeAuth.isAuthenticated?(
<p>
Welcome!
<button
onClick={() => {
// fakeAuth.signout(() => history.push("/protected"));
fakeAuth.signout(() => history.push("/protected")); //ログインに成功したら、サインアウトボタンを表示し、クリックするとログアウトメソッドが呼び出される isAuthenticatedがfalseに設定され、非同期のコールバック履歴が表示される.push ページジャンプをする
}}
>
Sign out
</button>
</p>
):(
//ログインに失敗した場合は、ログインしていないことを示す。
<p>You are not logged in.</p>
)
}
//カスタム・ハイレベル・ルーティング・コンポーネント{children, ...rest} children は、すべての子コンポーネントの下にある親コンポーネントがProtectedPageコンポーネントを指すことを示している。...rest は親コンポーネントのすべての属性(この場合はpath)である。="/protected"
function PrivateRoute( {children,...rest} ) {
// let history = useHistory();
// console.log("history:",history)
return (
<Route
{...rest}
render={({ location }) =>
fakeAuth.isAuthenticated ? (
children
) : ( // ここでは、ログアウトしたAuthButtonコンポーネントのonClickイベントを変更して、それを/protected このようにして、コンポーネントの切り替えを見ることができる。
<Redirect
to={{
pathname: "/login",
state: { from: location }
}}
/>
)
}
/>
);
}
//パブリックページコンポーネント
function PublicPage() {
return <h3>Public</h3>;
}
//保護されたページコンポーネント
function ProtectedPage() {
return <h3>Protected</h3>;
}
//ログインページコンポーネント
function LoginPage() {
let history = useHistory();
let location = useLocation();
// console.log("history:",history)
// console.log("location:",location)
//state属性がある場合は.state formはfromに割り当てられ、そうでない場合はデフォルトでfromに割り当てられる。{pathname:"/"}
let { from } = location.state || { from: { pathname: "/" } };
//ログインメソッド 定義されたfakeAuthログインメソッドを呼び出す コールバックでルーティングアドレスを変更する
//履歴.replace 履歴を持つ.push 非常によく似ているが、唯一の違いは、新しいレコードを履歴に追加するのではなく、現在の履歴レコードを置き換えることだ。
let login = () => {
fakeAuth.authenticate(() => {
history.replace(from);
// history.push(from.pathname)
});
};
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={login}>Log in</button>
</div>
);
}
保護されたコンポーネントの内部で、historyとlocationの値を以下のように出力します。
locationは、ルートの属性を含む、現在のURLのロケーションオブジェクトであることがわかります。
CustomRouter(Auth) -- カスタムルーティング
カスタムルーティングの最も一般的なシナリオは、アプリの下部にあるタブバーです。 タブバーが選択されているかどうかに応じて、タブバーのスタイルを変更できます。
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch
} from "react-router-dom";
export default class CustomLink extends Component {
render() {
return (
<Router>
<div>
<OldSchoolMenuLink
activeOnlyWhenExact={true}
to="/"
label="Home"
/>
<OldSchoolMenuLink to="/about" label="About" />
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
</div>
</Router>
)
}
}
function OldSchoolMenuLink({ label, to, activeOnlyWhenExact }) {
let match = useRouteMatch({
path: to,
exact: activeOnlyWhenExact
});
return (
<div className={match ? "active" : ""}>
{match && "> "}
<Link to={to}>{label}</Link>
</div>
);
}
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
PreventRouter -- ルートをブロック
このコンポーネントは、次のシナリオで使用されます。フォームに入力する際、ページをクリックして戻るとデータが失われます。 このコンポーネントは、ジャンプページをブロックするために使用します。 キャンセル] をクリックすると、フォームは元のページに残り、データは失われません。 OKをクリックすると、次のページにジャンプします。 データは失われます。 これは実際には二重確認ポップアップコンポーネントです。
import React, { Component, useState } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Prompt
} from "react-router-dom";
export default class PreventRouter extends Component {
render() {
return (
<Router>
<ul>
<li>
<Link to="/">From</Link>
</li>
<li>
<Link to="/one">One</Link>
</li>
<li>
<Link to="/two">Two</Link>
</li>
</ul>
<Switch>
<Route path="/" exact children={ <BlockingForm /> } />
<Route path="/one" children={<h3>One</h3>} />
<Route path="/two" children={<h3>Two</h3>} />
</Switch>
</Router>
)
}
}
function BlockingForm() {
//isBlockingというロッキング変数を定義する。 変更方法はsetIsBlockingで、デフォルトではfalseになっている。
let [isBlocking, setIsBlocking] = useState(false);
return(
//フォームイベントを送信する.preventDefault()デフォルトでコミットイベントをブロックする;
//event.target.reset() フォームの内容をリセットする
//setIsBlocking(false) isBlockingをfalseに設定する;
//Prompt コンポーネントブロックの遷移が={isBlocking} 文字通り、isBlockingがtrueの場合、childrenよりも優先される。
// message contentはポップアップウィンドウの内容である。
<form
onSubmit={event => {
event.preventDefault();
event.target.reset();
setIsBlocking(false);
}}
>
<Prompt
when={isBlocking}
message={location =>
`Are you sure you want to go to ${location.pathname}`
}
/>
<p>
Blocking?{" "}
{isBlocking ? "Yes, click a link or the back button" : "Nope"}
</p>
<p>
<input
size="50"
placeholder="type something to block transitions"
onChange={event => {
setIsBlocking(event.target.value.length > 0);
}}
/>
</p>
<p>
<button>Submit to stop blocking</button>
</p>
</form>
)
}
- Prompt コンポーネントの message 属性は、ジャンプ先のルートを決定し、プロンプトを出さずに true を返し、逆にプロンプトをポップアップする関数を受け取ることもできます。
<Prompt
when={isBlocking}
message={location =>
location.pathname=="/one"
? true
:
`Are you sure you want to go to ${location.pathname}`
}
/>
以下は、クリック2のポップアッププロンプトを入力した後のフォームデータです。
NoMatchRouter(404) -- 一致しないルート
マッチしないルートが選択された場合、デフォルトで本装置の最後のルートに移動します。 マッチルールは
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect,
useLocation
} from "react-router-dom";
export default class NomatchRouter extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/old-match">Old Match, to be redirected</Link>
</li>
<li>
<Link to="/will-match">Will Match</Link>
</li>
<li>
<Link to="/will-not-match">Will Not Match</Link>
</li>
<li>
<Link to="/also/will/not/match">Also Will Not Match</Link>
</li>
</ul>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/old-match">
<Redirect to="/will-match" />
</Route>
<Route path="/will-match">
<WillMatch />
</Route>
<Route path="*">
<NoMatch />
</Route>
</Switch>
</div>
</Router>
)
}
}
function Home(){
return <h3>Home</h3>
}
function WillMatch(){
return <h3>Matched!!</h3>
}
function NoMatch(){
let location = useLocation();
return (
<div>
<h3>
No match for {location.pathname}
</h3>
</div>
)
}
通常、実際には、マッチしないアイテムは1つの404エラールートページにリダイレクトされます。 ここでは、最後のRouteをRedirectに置き換えることができます。
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/old-match">
<Redirect to="/will-match" />
</Route>
<Route path="/will-match">
<WillMatch />
</Route>
<Route path="/error">
<Error />
</Route>
<Redirect from="/*" to="/error" />
</Switch>
RecursiveRouter -- 再帰ルーティング
再帰ルートは単にネストされたルートです。 再帰ツリーのようなもので、親ルートは子ルートを持ち、さらに子ルートを持ち...。 といった具合です。 公式のデモは、0,1,2,3個のオブジェクトの配列で、それぞれが友達のサブ配列を持ち、サブ配列0,1,2,3は親配列の各オブジェクトに対応しています。
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
useParams,
useRouteMatch
} from "react-router-dom";
export default class RecursiveRouter extends Component {
render() {
return (
<Router>
<Switch>
<Route path="/:id">
<Person />
</Route>
<Route path="/">
<Redirect to="/0" />
</Route>
</Switch>
</Router>
)
}
}
function Person(){
let { url } = useRouteMatch();
let { id } = useParams();
let person = find(parseInt(id));
return(
<div>
<h3>{person.name}'s Friends</h3>
<ul>
{
person.friends.map(
id=>
(
<li key={id}>
<Link to={`${url}/${id}`}>{find(id).name}</Link>
</li>
)
)
}
</ul>
<Switch>
<Route path={`${url}/:id`}>
<Person />
</Route>
</Switch>
</div>
)
}
const PEEPS = [
{ id: 0, name: "Michelle", friends: [1, 2, 3] },
{ id: 1, name: "Sean", friends: [0, 3] },
{ id: 2, name: "Kim", friends: [0, 1, 3] },
{ id: 3, name: "David", friends: [1, 2] }
];
function find(id){
return PEEPS.find(p=>p.id===id)
}
つまり、ここでアロー関数 => を書くとき、慣習的に => の後に {} を追加するとエラーになります。
SidebarRouter -- サイドバーのルーティング
サイドバーは、ページ表示の非常に一般的なタイプですが、私はここで公式の列になります少し変更CustomRouterのカスタムリンクメソッドを適用し、関数の背景色に小さなクリックを行います。
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch
} from "react-router-dom";
import "../App.css"
const routes = [
{
path:"/home",
exact:true,
sidebar: ()=><div>home?!</div>,
main: ()=><h2>Home</h2>
},
{
path:"/bubblegum",
sidebar: ()=><div>bubblegum?!</div>,
main: ()=><h2>Bubblegum</h2>
},
{
path:"/shoelaces",
sidebar: ()=><div>shoelaces?!</div>,
main: ()=><h2>Shoelaces</h2>
},
]
export default class SidebarRouter extends Component {
render() {
return (
<Router>
<div style={{display:"flex"}}>
<div style={{padding:"10px",width:"40%",background: "#f0f0f0"}}>
<ActiveLink
activeOnlyWhenExact={false}
to="/home"
label="Home"
/>
<ActiveLink
to="/bubblegum"
label="Bubblegum"
/>
<ActiveLink
to="/shoelaces"
label="Shoelaces"
/>
<Switch>
{
routes.map((route,index)=>(
<Route
key={index}
path={route.path}
exact={route.exact}
children={<route.sidebar />}
/>
))
}
</Switch>
</div>
<div style={{ flex: 1, padding: "10px" }}>
<Switch>
{
routes.map((route,index)=>(
<Route
key={index}
path={route.path}
exact={route.exact}
children={<route.main />}
/>
))
}
</Switch>
</div>
</div>
</Router>
)
}
}
function ActiveLink({ label, to, activeOnlyWhenExact }){
let match = useRouteMatch({
path: to,
exact: activeOnlyWhenExact
});
return(
<div className={match ? "bg_color_blue" : ""}>
{match && "!!"}
<Link to={to}>{label}</Link>
</div>
)
}
cssスタイルはApp.cssで直接参照されます。
.bg_color_blue{
background-color: skyblue;
}
コンフィグルーター -- ConfigRouter
実際のアプリケーションのほとんどは、ルーティングを一元的に設定します。
import React, { Component } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
//ルートコンフィギュレーションを定義する
const routes = [
{
path:"/sandwiches",
component: Sandwiches
},
{
path: "/tacos",
component: Tacos,
routes: [
{
path: "/tacos/bus",
component: Bus
},
{
path: "/tacos/cart",
component: Cart
}
]
}
]
export default class ConfigRouter extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/tacos">Tacos</Link>
</li>
<li>
<Link to="/sandwiches">Sandwiches</Link>
</li>
</ul>
<Switch>
{
routes.map((route,i)=>(
<RouteWithSubRoutes key={i} {...route} />
))
}
</Switch>
</div>
</Router>
)
}
}
function RouteWithSubRoutes(route){
return (
<Route
path={route.path}
render={props=>(
<route.component {...props} routes={route.routes} />
)}
/>
)
}
function Sandwiches() {
return <h2>Sandwiches</h2>;
}
// 親コンポーネントのroutesプロパティ
function Tacos({ routes }) {
return (
<div>
<h2>Tacos</h2>
<ul>
<li>
<Link to="/tacos/bus">Bus</Link>
</li>
<li>
<Link to="/tacos/cart">Cart</Link>
</li>
</ul>
<Switch>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
</Switch>
</div>
);
}
function Bus() {
return <h3>Bus</h3>;
}
function Cart() {
return <h3>Cart</h3>;
}
ルートには render と child があります。
render={()=>{return <div></div>}}render は関数で、構文は: 、ルートがマッチする限り、この関数が実行されます。
children も関数で、マッチするかどうかにかかわらず、この関数が実行されます。 これらは優先順位の関係を持っており、render の優先順位は children よりも常に高く、children の





