React Routerのチュートリアル Lesson10
前回の続き。
Lesson10 - Clean URLs with Browser History
これまで作ったアプリのURLは、ハッシュを使ったHackで成り立っています。これは常にうまく動作するデフォルトの挙動です。 しかし、もっと良い方法があります。
モダンなブラウザは、HTTPリクエストを生成することなくURLを操作することが可能です。
browserHistoryを使う
app/index.jsxを開いて、以下のように変更しましょう。
hashHistoryをbrowserHistoryに変更しただけです。
ReactDOM.render((
<Router history={browserHistory}>
これだけでクリーンなURLでアクセスすることができます。 しかしこの方法には罠があります。 何らかのリンクをクリックしたのち、ブラウザをリフレッシュしてみましょう。 すると404 Not Foundが発生するはずです。
404 Not Foundの解決方法
webpack-dev-serverの起動オプションに、--history-api-fallbackをつける。
package.jsonを開いて、以下のように変更します。
"scripts": {
"start": "webpack-dev-server --inline --content-base . --history-api-fallback",
},
scriptタグのsrcに指定しているbundle.jsのパスを変更する。
html-webpack-pluginを使っているので、webpack.config.jsを変更します。
以下のように、filenameを変更します。
output: {
path: PATHS.build,
filename: '/bundle.js'
},
まとめ
browserHistoryを使えば、クリーンなURLを使うことができる。
ソースコード
React Routerのチュートリアル Lesson9
前回の続き。
Lesson9 - Index Links
今回は、ナビゲーションリンクにHomeリンクを追加して、どの画面からでもホーム画面に戻れるようにします。
最初に思いつく方法
単純にapp/components/app.jsxに、ホーム画面へのリンクを追加する方法です。
<li><NavLink to="/">Home</NavLink></li>
しかし、この方法には問題があります。
AboutをクリックしてもReposをクリックしても、常にHomeがアクティブな状態になることです。
なぜなら、/は全てのURLの親だからです。
IndexLinkを使う
この問題を解決するために、React Routerが提供するIndexLinkを使います。
IndexLinkは、IndexRouteで設定されているURLへ遷移するためのリンクを生成してくれます。
先ほどの、ホーム画面へのNavLinkを削除して、以下を追加しましょう。
<li><IndexLink to="/" activeClassName="active">Home</IndexLink></li>
すると、期待通りに動作するかと思います。
LinkコンポーネントのonlyActiveOnIndexプロパティを使う
もう一つの方法は、LinkコンポーネントのonlyActiveOnIndexを使うことです。
すでに作成済みのNavLinkは、Linkコンポーネントのラッパーですが、スプレッド演算子でプロパティを展開しているので、以下のように書くことで実現することができます。
<li><NavLink to="/" onlyActiveOnIndex={true}>Home</NavLink></li>
まとめ
ソースコード
React Routerのチュートリアル Lesson8
前回の続き。
Lesson8 - Index Routes
これまでの実装では、/にアクセスすると、単にリンク一覧とBlankページが表示されるだけでした。
今回は、Homeコンポーネントを追加して、/にアクセスしたときにHome画面を表示します。
方法1
子要素がないときには、Homeコンポーネントをレンダリングする方法です。
具体的には以下のように、{ this.props.children || <Home /> } とします。
class App extends React.Component {
render() {
return (
<div>
<h1>React Router Tutorial</h1>
<ul role="nav">
<li><NavLink to="/about">About</NavLink></li>
<li><NavLink to="/repos">Repos</NavLink></li>
</ul>
{ this.props.children || <Home /> }
</div>
);
}
}
Homeコンポーネントは以下です。
import React from 'react';
class Home extends React.Component {
render() {
return (<div>Home</div>);
}
}
export default Home;
方法2
もう一つの方法は、React Routerが提供するIndexRouteを使う方法です。
方法1のコードを削除して、app/index.jsxを以下のように変更してみます。
ReactDOM.render((
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="/repos" component={Repos}>
<Route path="/repos/:userName/:repoName" component={Repo} />
</Route>
<Route path="/about" component={About} />
</Route>
</Router>
), document.body.appendChild(document.createElement('div')));
IndexRouteにはパスが設定されません。
IndexRouteは、親のパスに正確に一致する場合にレンダリングするコンポーネントを表示します。
ソースコード
React Routerのチュートリアル Lesson7
前回の続き。
Lesson7 - More Nesting
今回は、前回追加したパラメータ付きリンクのクリック時の挙動を、ちょっとだけ変更します。 リンクをクリックすると、その下にリンクしたリポジトリ名を表示するようにします。
ネストを変更する
Reposの子要素にRepoを配置します。
... (snip) ...
<Route path="/repos" component={Repos}>
<Route path="/repos/:userName/:repoName" component={Repo} />
</Route>
... (snip) ...
子要素をリンクの下に描画する
this.props.childrenで、Reposの子要素を描画します。
ついでに、LinkをNavLinkに置き換えて、リンクのアクティブな状態がわかるように変更します。
class Repos extends React.Component {
render() {
return (
<div>
<h2>Repos</h2>
<ul>
<li><NavLink to="/repos/reactjs/react-router">React Router</NavLink></li>
<li><NavLink to="/repos/facebook/react">Facebook</NavLink></li>
</ul>
{ this.props.children }
</div>
);
}
}
export default Repos;
まとめ
特になし。
ソースコード
React Routerのチュートリアル Lesson6
前回の続き。
Lesson6 - Params
今回のお題は、パラメータの渡し方です。
例えば、以下のようなURLを考えてみます。
/repos/reactjs/react-router /repos/facebook/react
これらのパラメータは、以下の形式にマッチします。
/repos/:userName/:repoName
これらのパラメータは、this.props.params[name]のように取得することができます。
渡されたパラメータを画面に表示してみる
まずは、Repoコンポーネントを作成します。
このコンポーネントは、渡されたパラメータrepoNameを単に表示するのみです。
import React from 'react';
class Repo extends React.Component {
render() {
return (
<div>
<h2>{this.props.params.repoName}</h2>
</div>
);
}
}
export default Repo;
次に、Routeをapp/index.jsxに追加します。
... (snip) ...
ReactDOM.render((
... (snip) ...
<Route path="/repos/:userName/:repoName" component={Repo} />
... (snip) ...
),
document.body.appendChild(document.createElement('div'))
);
Repoを表示するリンクを追加する
app/components/repos.jsxに、Repoを表示するリンクを追加します。
import React from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router';
export default class Repos extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h2>Repos</h2>
<ul>
<li><Link to="/repos/reactjs/react-router">React Router</Link></li>
<li><Link to="/repos/facebook/react">Facebook</Link></li>
</ul>
</div>
);
}
}
リンクをクリックすると、それぞれのrepoNameが表示されるはずです。
まとめ
- パラメータ名は、コロンで始まる変数名を含め、Routeに割り付けてあげる。
ソースコード
React Routerのチュートリアル Lesson5
前回の続き。
Lesson5 - Active Links
今回は、アクティブなリンクにスタイルを適用して、アクティブなリンクをわかりやすく表示してみます。
Linkにスタイルを適用する
ハイパーリンクにスタイルを与えるには、LinkコンポーネントのactiveStyleというPropを設定してあげます。
import React from 'react';
import { Link } from 'react-router';
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>React Router Tutorial</h1>
<ul role="nav">
<li><Link to="/about" activeStyle={{ color: 'red' }}>About</Link></li>
<li><Link to="/repos" activeStyle={{ color: 'red' }}>Repos</Link></li>
</ul>
{ this.props.children }
</div>
);
}
}
export default App;
これで、アクティブなリンクが赤色で表示されます。
別の手段でスタイルを適用する
上記とは別に、activeClassNameというPropsを使う方法もあります。
この方法は、Linkにclassを設定して、スタイルは別途スタイルシートで定義する方法です。
まずは、activeStyleをactiveClassNameに置き換えます。与えるclass名はactiveにします。
import React from 'react';
import { Link } from 'react-router';
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>React Router Tutorial</h1>
<ul role="nav">
<li><Link to="/about" activeClassName="active">About</Link></li>
<li><Link to="/repos" activeClassName="active">Repos</Link></li>
</ul>
{ this.props.children }
</div>
);
}
}
export default App;
次に、スタイルシートapp/index.cssを作成し、スタイルを定義します。
.active {
color: green;
}
最後に、app/index.cssをapp/index.jsxで読み込みます。
... (snip) ...
require('./index.css');
... (snip) ...
今度は、アクティブなリンクが緑色で表示されるようになります。
Linkコンポーネントのラッパーを作る
LinkにいちいちactiveClassNameを渡すのはDRYじゃないですので、LinkのラッパーコンポーネントNavLinkを作ります。
import React from 'react';
import { Link } from 'react-router';
class NavLink extends React.Component {
render() {
return (<Link {...this.props} activeClassName="active" />);
}
}
export default NavLink;
NavLinkでLinkを置き換えます。
import React from 'react';
import NavLink from './nav_link'
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>React Router Tutorial</h1>
<ul role="nav">
<li><NavLink to="/about">About</NavLink></li>
<li><NavLink to="/repos">Repos</NavLink></li>
</ul>
{ this.props.children }
</div>
);
}
}
export default App;
まとめ
- アクティブなリンクにスタイルを適用するには、
LinkコンポーネントのactiveStyleまたはactiveClassNameを使う。 activeStyleでは、スタイルを直接設定する。activeClassNameではclass名を設定し、スタイルは別途スタイルシートで設定する。Linkコンポーネントは、自身がアクティブか否かを知っているので、ラッパーを作ればactiveClassNameの指定をいちいちしなくて良い。
ソースコード
上記のリリースではNavLinkを入れ忘れたので、下記で対応。
React Routerのチュートリアル Lesson4
前回の続き。
Lesson 4 - Nested Routes
今回は、Lesson3で追加したハイパーリンクを、全ての画面に表示します。
ReposとAboutをAppの子要素に配置する
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, hashHistory } from 'react-router';
require('../node_modules/bootstrap/dist/css/bootstrap.css');
import App from './components/app';
import About from './components/about';
import Repos from './components/repos';
ReactDOM.render((
<Router history={hashHistory}>
<Route path="/" component={App}>
<Route path="/repos" component={Repos} />
<Route path="/about" component={About} />
</Route>
</Router>
),
document.body.appendChild(document.createElement('div'))
);
Appで子要素ReposとAboutをレンダリングする
import React from 'react';
import { Link } from 'react-router';
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>React Router Tutorial</h1>
<ul role="nav">
<li><Link to="/about">About</Link></li>
<li><Link to="/repos">Repos</Link></li>
</ul>
{ this.props.children }
</div>
);
}
}
export default App;
まとめ
- ハイパーリンク(には限らないけれども)を全ての画面で表示するためには以下をする