react-routerを使ってページ遷移(@第3回 Reactハンズオン 初等部編)

#react-routerとは？

* Reactのルーティングライブラリのデファクトスタンダード
* Reactで擬似的なページ遷移を可能にする

GitHub
https://github.com/ReactTraining/react-router

今回のサンプル
https://github.com/takanorip/react-router-sample

#書き方

まずReactとreact-routerをimportします。
今回は`browserHistory`を使います。(ブラウザのHistory APIを使ってルーティングします。)

```js:App.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import { IndexRoute, Link, Router, Route, browserHistory } from 'react-router';
```

次にリンク部分を書きます。
リンクを付けたい部分に`<Link>`タグを書くだけです。レンダリング後はこの部分に`a`タグが入ります。

```js:App.js
class App extends Component {
  render() {
    return (
      <div>
        <ul>
          <li><Link to="/">TOP</Link></li>
          <li><Link to="/about">ABOUT</Link></li>
          <li><Link to="/works">WORKS</Link></li>
        </ul>
        <div>
          { this.props.children }
        </div>
      </div>
    );
  }
}
```

最後にレンダリング部分を書きます。
react-routerを使うときは普通に`<App />`のように書くのではなく`Router`と`Route`を使用して書きます。
`Route`が遷移するページに対応しています。
`<IndexRoute >`を使うと`/`のときにTOPに飛ばしてくれます。
 
```js:App.js
render((
    <Router history={browserHistory}>
        <Route path="/" component={App}>
            <IndexRoute component={Top} />
            <Route path="/about" component={About} />
            <Route path="/works" component={Works} />
        </Route>
    </Router>
), document.querySelector('#app'));
```



###全体

```js:App.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import { IndexRoute, Link, Router, Route, browserHistory } from 'react-router';

import styl from './App.styl';

class App extends Component {
  render() {
    return (
      <div className="main">
        <ul className="navi">
          <li className="navi__bt"><Link to="/">TOP</Link></li>
          <li className="navi__bt"><Link to="/about">ABOUT</Link></li>
          <li className="navi__bt"><Link to="/works">WORKS</Link></li>
        </ul>
        <div className="text">
          { this.props.children }
        </div>
      </div>
    );
  }
}

class Top extends Component {
  render() {
    return <div>Top</div>;
  }
}

class About extends Component {
  render() {
    return <div>About</div>;
  }
}

class Works extends Component {
  render() {
    return <div>Works</div>;
  }
}

render((
  <Router history={browserHistory}>
    <Route path="/" component={App}>
      <IndexRoute component={Top} />
      <Route path="/about" component={About} />
      <Route path="/works" component={Works} />
    </Route>
  </Router>
), document.getElementById('app'));
```

##注意点

今回 `browserHistory` を使用しているため、404になったとき `index.html` に戻してあげる設定をする必要があります。
このままだと、その処理が書かれていないので、TOP以外のアドレスを直打ちしたりリロードしたりすると`Cannot GET /XXX`となってしまいます。

設定方法はサーバーごとに違いますが、
webpack-dev-serverを使うなら `--history-api-fallback` という起動オプションを追加すればOKです。

#Reactにおけるルーティングのその他の方法

###ui-router
もともとAngular.jsのルーティングに使用されているモジュールですが、最近Reactでも使えるようになりました。
ui-routerで書くとこんな感じになります。

```js:App.js
import React from 'react';
import ReactDOM from 'react-dom';
import UIRouterReact, {UIView, UISref, UISrefActive} from 'ui-router-react';

import stylus from './App.styl';


const router = new UIRouterReact();

const topState = {
  name: 'top',
  url: '/',
  component: () => <div>top</div>
}

const aboutState = {
  name: 'about',
  url: '/about',
  component: () => <div>about</div>
}

const worksState = {
  name: 'works',
  url: '/works',
  component: () => <div>works</div>
}

router.stateRegistry.register(topState);
router.stateRegistry.register(aboutState);
router.stateRegistry.register(worksState);

router.start();

ReactDOM.render(
  <div>
    <UISrefActive class="active">
      <UISref to="top"><a>TOP</a></UISref>
    </UISrefActive>
    <UISrefActive class="active">
      <UISref to="about"><a>ABOUT</a></UISref>
    </UISrefActive>
    <UISrefActive class="active">
      <UISref to="works"><a>WORKS</a></UISref>
    </UISrefActive>

    <UIView/>
  </div>,
  document.getElementById('app')
);

```


###何も使わない

https://medium.com/@dabit3/beginner-s-guide-to-react-router-53094349669#.hgngpfr9s


#補足
##v4での書き方

まだ正式にリリースされていませんが、react-router@next(v4)が現在公開されています。
https://react-router.now.sh/
https://github.com/ReactTraining/react-router/tree/v4

v4ではかなり大きな変更があるらしく、書き方も大きく変わります。

上で書いたものをv4版に書き直すと下記のようになります。

```js:App.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Match, Miss, Link } from 'react-router'


class Top extends Component {
  render() {
    return <div>Top</div>;
  }
}

class About extends Component {
  render() {
    return <div>About</div>;
  }
}

class Works extends Component {
  render() {
    return <div>Works</div>;
  }
}

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <div>
          <ul>
            <li><Link to='/'>Top</Link></li>
            <li><Link to='/about'>About</Link></li>
            <li><Link to='/works'>Works</Link></li>
          </ul>
          <div className="text">
            { this.props.children }
          </div>
          <Match exactly pattern='/' component={Top} />
          <Match pattern='/about' component={About} />
          <Match pattern='/works' component={Works} />
        </div>
      </BrowserRouter>
    );
  }
}

render((
  <App />
), document.getElementById('app'));
```