JavaScript
reactjs
react-router

大幅変更されそうな react-router @ next (v4) 覗き見メモ

More than 1 year has passed since last update.


ざっくり


  • 基本今までのと全部違うと言っていいぐらい違う

  • めっちゃコード量減ってる

  • 旧バージョンからアップデートするとなると結構書き換えは必要そうかも


installして試したかったら?

$ npm install react-router@next


package.json から見る構造変更


  • v2(現行)



    • historyに依存しており、<Router />にはhistoryオブジェクトを渡す必要があった。

    • 内部でhistoryとの結合とかを色々やってた。



  • v4




Quick start比較

それぞれざっくり特徴が見えるところを抜粋


v2

import React from 'react'

import { render } from 'react-dom'
import { Router, Route, Link, browserHistory } from 'react-router'

render((
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="about" component={About}/>
<Route path="users" component={Users}>
<Route path="/user/:userId" component={User}/>
</Route>
<Route path="*" component={NoMatch}/>
</Route>
</Router>
), document.getElementById('root'))


v4

quick-start (v4) からざっくり抜粋

import React from 'react'

import { render } from 'react-dom'

import { BrowserRouter, Match, Miss, Link } from 'react-router'

const App = () => (
<BrowserRouter>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<Match exactly pattern="/" component={Home} />
<Match pattern="/about" component={About} />
<Match pattern="/topics" component={Topics} />
<Miss component={NoMatch}/>
</div>
</BrowserRouter>
)

render(<App/>, document.querySelector('#root'))

historyを渡さず、Componetとして定義出来るようになったことかなりのすっきり感がある。

<Match>のルールも子コンポーネントで更に定義するなどもあって、親<Router />が全体のRoutingを把握しなくても良くなっているっぽい

また、<div>などの標準的な記法と<Match/>の組み合わせで作られているので、HeaderやFooterやMenuなどの組み合わせがやりやすい。

https://react-router-website-xvufzcovng.now.sh/basic


ファイル数

### v2

% git clone https://github.com/ReactTraining/react-router.git
% ls -1 modules/ | grep .js | wc -l
38

### v4
% git co v4
% ls -1 modules/ | grep .js | wc -l
16

38 -> 16 と大激減!

多けりゃいい少なけりゃいいというものではないけど、内容としても見通しがよく感じる。

かなり読みやすいと感じた。

historyとのつなぎ込み部分がreact-historyに移動されたことで減った部分が多い模様。


ロゴ

青かったのが赤くなった


ハマりどころ:<Router/>の直下は単一のコンポーネントである必要がある

ちょっと使って見つけた部分。

MatchProvider.render(): A valid React element (or null) must be returned. 

You may have returned undefined, an array or some other invalid object.

こんなエラーが出てきてなんだろうなーと思ったら<Router />直下のComponentは一つのコンポーネントでないといけない。なので<div></div>とかで囲まないといけない。

これは仕様らしい。

https://github.com/ReactTraining/react-router/issues/3837#issuecomment-246919642

// ダメ

const BadRoute = () => (
<Router>
<Match pattern="/" component={Foo} />
<Match pattern="/:bar" component={Baz} />
</Router>
)

// ダメ

const BadRoute = () => (
<Router>
<div>
<Match pattern="/" component={Foo} />
<Match pattern="/:bar" component={Baz} />
</div>
<div></div>
</Router>
)

// これならOK

const Route = () => (
<Router>
<div>
<Match pattern="/" component={Foo} />
<Match pattern="/:bar" component={Baz} />
</div>
</Router>
)


FAQより「なんで巨大な変更をするのか?」

2016/09/16追記項目

FAQ がREADMEに追加された。最初の項目に関して結構思想的な背景が見える部分だったので、雑訳してみる。

2016/09/16追記:FAQ がREADMEに追加された。最初の項目に関して結構思想的な背景が見える部分だったので雑訳。


  • Q. なんで巨大な変更するのか?

  • A. tl; dr: Declarative Composability(宣言的構築性?)のため


    • 「我々はReact Routerでわくわくしたことなかった」

    • 「私達が学んだことは、Reactの最も愛すべき理由が Declarative Composabillityであることです」


      • 要するにReactと同じように、宣言的に記述出来るのが良いよね。という感じっぽい。



    • 「staticなrouterのconfigをしないといけないせいで、下記のようなルーターは書けなかったし、Routeをラップすることもできなかった」


      • const CoolRoute = (props) => <Route {...props} cool={true}/>

      • 宣言的な記述でない例として、静的なrouting configを書かないといけないことが弊害として上げられているものと思われる。



    • 「routeコンポーネントのレンダリングに関与するために、<Router createElement render>とかcreateRouterMiddleware快適と言えないAPIを提供していた。我々はcreateElementを取り除き、あなたたちに返す」


      • うまく訳せないが、きっとAPIとしては提供しなくてもdeclarativeにすることで、「middlewareらへんはあなた達の好きな様にやってくれたらいい」という意味っぽく感じる。



    • onEnteronLeaveonChangeのライフサイクルフックを再作成していた。けどReactには既にcomponentWillMountcomponentWillReceivePropscomponentWillUnmuntがある」

    • 「Route configはviewヒエラルキーを記述していた。しかし、そもそもReact Componentは既にviewヒエラルキーを記述していた。」

    • 「今までのReact Routerは『Reactのルーター』ではなく、『Reactのルーティングフレームワーク』だった」1


      • 「Reactにとって余計なAPIだけでなく、ビルドエコシステムに対しても驚くほどやっかいな偶発的なフレームワークとなっていた」



    • 「あなたはcomponentをレンダリングしてpropsを渡すことでroutingをコントロール出来る。」







  1. 個人的にこの表現が「おー」ってなった。