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;
まとめ
- ハイパーリンク(には限らないけれども)を全ての画面で表示するためには以下をする