今回は、react-router-domを使って、Reactアプリで画面遷移をしてみようと思います!
Material-UIでreact-router-domを使う方法も解説しますので、Material-UIを使っている方も参考になると思います!
学習に使った本はこちら!
Amazon Kindle Unlimited でもReactの本はいっぱいあるぞ!
Reactの開発環境がまだできていない方は、こちらを参考にしてみてください!
サイトデザインに困っている方は、こちらを参考にMaterial-UIを導入してみてもいいと思います!!
画面を切り替えるということは、ほぼ必須だと思いますのでぜひ参考にしてみてください!
- Reactアプリで画面遷移を行いたい!
- react-router-domの使い方を知りたい!
- Material-UIでreact-router-domを使う方法が知りたい!
なぜreact-router-domが必要なのか?
なぜ、react-router-domが必要なんじゃ??
Reactアプリで画面遷移を行うために、なぜreact-router-domが必要なのかを少し説明しようと思います!
ReactはSPA(シングルページアプリケーション)を得意としているフレームワークです。
SPAは、初期ロード時に全ての情報を読み込むことで、初期ロード時に時間がかかってしまうが、一度ロードしてしまえばページリクエストをすることがなく動作スピードが向上します。
しかし、ページリクエストをしないので画面遷移をすることができなくなってしまいます。
それを解消するのがreact-router-domです。
Routingという機能を提供し、DOMを書き換えて複数ページがあるようにしてあげることを可能にしてくれます!
react-router-domを使ってみよう!
なぜ、react-router-domを使う必要があるのかを説明したので、早速実装してみましょう!!
react-router-domをインストールしていく!
まずは、react-router-domをnpmを使ってインストールしていきます!
下記のコマンドを実行してください!
C:\Users\*****\Documents\sample-react-app>npm install react-router-dom
コマンドを実行したら、package.jsonにreact-router-domが追記されていると思います!
package.json
{
"name": "sample-client",
"version": "0.1.0",
"private": true,
"dependencies": {
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.7.1",
"axios": "^0.21.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.2",
"web-vitals": "^1.1.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {}
}
ここまで確認できれば、インストールは完了です!
Linkを設定する!
Linkはreact-router-domのコンポーネントで、指定したpathにアクセスする設定をします!
せっかくなので、前回作ったヘッダーにボタンを配置してLinkを設定していきます!
もし、この記事から見始めるひとは、任意の場所にボタンを配置してLinkを設定してみてください!
Header.jsを開いて、下記のように修正します!
import でreact-router-domのLinkコンポーネントをインポートしています。
<Link>のtoに、アクセスしたいPathを記載します!
Header.js
import React from 'react'
import { Link } from 'react-router-dom'
import { makeStyles, withStyles } from '@material-ui/core/styles'
import {
AppBar,
Toolbar,
Typography,
Button,
IconButton,
Box,
} from '@material-ui/core'
import { Menu as MenuIcon } from '@material-ui/icons'
const useStyles = (theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
})
class Header extends React.Component {
render() {
const { classes } = this.props
return (
<div className={classes.root}>
<AppBar position="relative">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="menu"
>
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
<Box textAlign="left">SampleTitle</Box>
</Typography>
<Button color="inherit">
<Link to="/sample1">sample1</Link>
</Button>
<Button color="inherit">
<Link to="/sample2">sample2</Link>
</Button>
</Toolbar>
</AppBar>
</div>
)
}
}
RouterとRouteを設定していく!
続いて、RouterとRouteを設定していきます。
Routerは、react-router-domのコンポーネント(Route,Link)を使えるようにするためのコンポーネントです。
なので、上位の階層(App.jsなど)で設定することが多いです。
Routeは、pathに指定したURLと現在のURLが一致するときにUIを表示させてあげるコンポーネントです。
App.jsを下記のように修正し、いくつかSample画面を作成しておきます!
App.js
import './App.css'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Header from './components/modules/Header'
import SampleRoot from './components/pages/SampleRoot'
import Sample1 from './components/pages/Sample1'
import Sample2 from './components/pages/Sample2'
function App() {
return (
<div className="App">
<Router>
<Header />
<Route path="/" component={SampleRoot} />
<Route path="/sample1" component={Sample1} />
<Route path="/sample2" component={Sample2} />
</Router>
</div>
)
}
export default App
サンプルの画面は、components>modules>pages配下に作成してください!
SampleRoot.js
import React from 'react'
class SampleRoot extends React.Component {
render() {
return <div>Rootで表示されてほしい内容!</div>
}
}
export default SampleRoot
Sample1.js
import React from 'react'
class Sample1 extends React.Component {
render() {
return <div>sample1で表示されてほしい内容!</div>
}
}
export default Sample1
Sample2.js
import React from 'react'
class Sample2 extends React.Component {
render() {
return <div>sample2で表示されてほしい内容!</div>
}
}
export default Sample2
ここまでできれば、設定は完了なので実際に確認してみましょう!
確認してみる!
まずは、「http://localhost:3000」を確認しましょう!
ヘッダーの右端に、SAMPLE1とSAMPLE2というボタンが表示されていますね!!
また、path=”/”の内容である、SampleRoot.jsが表示されていると思います!
続いて、SAMPLE1のボタンを押してみましょう!
「http://localhost:3000/sample1」に遷移すると思います!
ただ、画面は、path=”/sample1″の内容だけでなく、path=”/”も表示されてしまっていると思います。
念のため、SAMPLE2も確認してみましょう!
「http://localhost:3000/sample2」に遷移はすると思います。
こちらも、画面は、path=”/sample2″の内容だけでなく、path=”/”も表示されてしまっていますね。
なぜかというと、 <Link>のpathは、部分一致なので 「/sample1」だと 「/」も「/sample1」も一致したとみなされてしまうのです。
pathを完全一致にしてみよう!
では、完全一致にするにはどうしたらいいかというと、exactをつけてあげればいいだけです!
App.jsを下記のように修正してみてください!
App.js
import './App.css'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Header from './components/modules/Header'
import SampleRoot from './components/pages/SampleRoot'
import Sample1 from './components/pages/Sample1'
import Sample2 from './components/pages/Sample2'
function App() {
return (
<div className="App">
<Router>
<Header />
<Route exact path="/" component={SampleRoot} />
<Route exact path="/sample1" component={Sample1} />
<Route exact path="/sample2" component={Sample2} />
</Router>
</div>
)
}
export default App
これで再度確認してみましょう!
「http://localhost:3000」の時は、前回と同様にpath=”/”のSampleRoot.jsの内容のみが表示されていますね!
「http://localhost:3000/sample1」の時も、path=”/sample1″のSample1.jsの内容のみが表示されていることが確認できたと思います!
「http://localhost:3000/sample2」の時も、path=”/sample2″のSample2.jsの内容のみが表示されていることが確認できてますよね!
ボタンを修正しよう!
先ほどLinkを設定したボタンを、よくみてもらうとわかるのですがリンク表示されてしまっていますよね。
Material-UIでreact-router-domのLinkを設定する場合の記述と異なるために起きてしまっているので、これを修正していこうと思います。
Material-UIを使っていない方は、飛ばしてもらって構いません!
Header.jsを下のように修正します!
Header.js
import React from 'react'
import { Link } from 'react-router-dom'
import { makeStyles, withStyles } from '@material-ui/core/styles'
import {
AppBar,
Toolbar,
Typography,
Button,
IconButton,
Box,
} from '@material-ui/core'
import { Menu as MenuIcon } from '@material-ui/icons'
const useStyles = (theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
})
class Header extends React.Component {
render() {
const { classes } = this.props
return (
<div className={classes.root}>
<AppBar position="relative">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="menu"
>
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
<Box textAlign="left">SampleTitle</Box>
</Typography>
<Button color="inherit" component={Link} to="/sample1">
sample1
</Button>
<Button color="inherit" component={Link} to="/sample2">
sample2
</Button>
</Toolbar>
</AppBar>
</div>
)
}
}
export default withStyles(useStyles)(Header)
Material-UIのButtonコンポーネントにcomponent={Link} to=”Path”を指定することでMaterial-UIでLinkを使うことが可能になります。
これで、確認してみましょう!
ちゃんとリンク表記ではない表記になりましたね!!
【おまけ】Switchを使ってみる!
先ほど、exactを使うと完全一致になると説明したと思いますが、もし完全一致が複数ある場合(こんなことはまずないと思いますが)は、どうなるでしょうか。
App.js
import './App.css'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Header from './components/modules/Header'
import SampleRoot from './components/pages/SampleRoot'
import Sample1 from './components/pages/Sample1'
import Sample2 from './components/pages/Sample2'
function App() {
return (
<div className="App">
<Router>
<Header />
<Route exact path="/" component={SampleRoot} />
<Route exact path="/sample1" component={Sample1} />
<Route exact path="/sample1" component={Sample1} />
<Route exact path="/sample2" component={Sample2} />
</Router>
</div>
)
}
export default App
こんなコードだった場合に、どうなるか確認してみましょう!
一致しているもの全てを表示することになってしまいますね。
これはこれでいいのですが、Switchを使うことで最初に一致したものだけを表示するということが可能になります。
App.js
import './App.css'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import Header from './components/modules/Header'
import SampleRoot from './components/pages/SampleRoot'
import Sample1 from './components/pages/Sample1'
import Sample2 from './components/pages/Sample2'
function App() {
return (
<div className="App">
<Router>
<Header />
<Switch>
<Route exact path="/" component={SampleRoot} />
<Route exact path="/sample1" component={Sample1} />
<Route exact path="/sample1" component={Sample1} />
<Route exact path="/sample2" component={Sample2} />
</Switch>
</Router>
</div>
)
}
export default App
こんな感じで、Switch を追加してみてください!
すると、最初の1つ目に一致したものだけが表示されると思います。
URL定義をちゃんとしていれば、必要のない機能だと思いますのでおまけにしましたが、
応用次第で色々なことができると思います!
まとめ
今回は、reace-router-domを使って、Reactアプリで画面遷移を行う方法を説明いたしました!
DOMを更新するだけなので、画面がロードされていないことも確認できたかなと思います!!
ほぼ必須と言っても過言ではない機能なので、ぜひ覚えてみてください!
学習に使った本はこちら!
Amazon Kindle Unlimited でもReactの本はいっぱいあるぞ!
次回は、APIを呼び出してデータを取得してみようと思います!