半空洞男女関係

思ったこととかプログラミングしてるときのメモとか色々かいてます。メールはidそのままgmail

react-routerのチュートリアルをやった

github.com

英語も簡単だし分かりやすくて良い。おすすめ。以下メモです。

React Router Tutorial

2: ルートを描画する

  • RouterRouteを管理する
    • Routeにはコンポーネントと対応するpathを渡す
    • RouterにはhashHistoryを渡してやる。historyは色々オブジェクト渡せそうなので履歴をいじったりも出来るのかな?

3: Linkでナビゲーション

  • react-routerに入っているLinkを使うとreact-routerで管理しているRouteへのリンクを作れる。

4: ネストしたルート

5: アクティブなリンク

  • あるリンクが選択されているときにスタイルを当てる。(例: 見ているルートのリンクは赤色にする)
    • activeStyle属性にCSSのobjectを渡せばOK.
    • activeClassName属性にクラス名を渡すと、アクティブになったときにそのクラス名が付く。style.cssとかで設定可能になる。
  • いちいちLinkactiveClassNameとか指定するの面倒だから、NavLinkというコンポーネントを作っちゃおう。

6: パラメータ

  • SinatraやExpressと同じように、URLに含まれた文字列を取得することができる。
    • Routepath属性には/repos/:userName/:repoNameという感じでいつもの用に指定する。
    • Routeで指定したcomponentpropsparamsというオブジェクトがあるのでそれを使えば良い: this.props.params

7: もっとネスト

  • 特に新しい事柄はなし。
  • Linkで指定したactiveClassなどは、親のLinkにも適用される。
    • たとえば、/users/10/starsへのLinkがあって、それがactiveになっている時、/users/10/starsLinkだけでなく、/users/10Linkにも適用されるというわけ。

8: インデックスのルート

  • 今の実装だと、あるRoute/には何もコンテンツが表示されないことになってしまう。
  • this.props.children が無いときに表示するコンテンツを用意しよう。
  • やり方は2つ。

|| で区切る

{this.props.children || <Home/>}

と書けばよい。これはシンプルでいいしうまく動くけど、以下の理由のために他のRouteと同じようにインデックスのルートを指定したい。

  1. routecomponentに応じてデータをfetchしてくるときのため
  2. onEnterをHookするため
  3. コードの分離のため

と、色々需要があるので、Routeみたいに指定したいぞ…。

IndexRouteを使う。

  • Routeの中で、他のRouteと同じようにIndexRouteを使う。
    • 注目すべきはIndexRouteの属性。pathはつけていない。
    • そして、this.props.childrenとして渡されている。

9: インデックスへのリンク

  • よくある「ロゴをクリックしたら/へ」の実装。
  • Linkで実装すると(我々はNavLinkを使っているので実際はそれだけど)、ずっとそのリンクがactiveになってしまう。(/はどのルートにも入っているので)
  • そこでIndexLinkを使う。
    • IndexLinkLinkをwrapしたもの。
    • LinkコンポーネントonlyActiveOnIndextrueを渡せば良い。
  • というわけで、NavLinkにもその機能は適用されるので、実は全部NavLinkで済む。
    • [thought] Reactは継承より構成を尊重すべきだったはずなので、色々な今ポー年tのができてしまうよりはこうしてカスタマイズでなんとかできたほうが良いと思う。

10: browserHistoryでURLをきれいに

でも…。

  • /reposにルートを切り替えて、リフレッシュすると404になる。
  • webpack-dev-server--history-api-fallbackをする。
  • すると/以外のpathでもindex.htmlが配信される。
    • nginxとかの場合はtry_filesとか使えば実装できる。
  • JSやCSSなど、assetのパスには注意。

11: 本番に似た環境でトライ

  • 実際はSSR(Server-side Rendering)したかったりするので、それの準備。
  • webpackしたものをexpressで配信する構成。
  • webpack側でoptimizeかけられる。
    • webpack.optimize.DedupePlugin(): 被ったモジュールは一つに。
    • webpack.optimize.OccurrenceOrderPlugin(): IDの桁数を減らしてサイズ節約
    • webpack.optimize.UglifyJsPlugin(): uglifyでminimizeする
    • ref: webpackを使い倒す - Thujikun blog
  • express側ではgzip圧縮するためにcompressionを使う。

12: プログラマティックに移動

  • 今まではLinkで移動してきたけど、ボタンクリックやフォーム送信などのタイミングで移動するようにしてみる。
  • browserHistory.push(path)を使えば良い。

There's a potential problem with this though. If you pass a different history to Router than you use here, it won't work. It's not very common to use anything other than browserHistory, so this is acceptable practice. If you're concerned about it, you can make a module that exports the history you want to use across the app, or...

の部分がいまいち理解できなかった…。

  • contextTypesに追加すると、this.context.routerでアクセスできるようになる。pushとかpopってmethodが生えてる。

なぜ contextTypes に追加すると this.context.router で諸々にアクセスできるのか

13: サーバーサイドでレンダリング

node.jsでJSX

  • nodeはJSXを理解しない(し、するべきでない)ので、コンパイルしないといけない。でもbabel/registerなどはproduction環境での利用にはフィットしない。
  • server用のbundleを作ろう。nodeのスクリプトもwebpackしてから実行する。

コードを分ける

  • サーバーとクライアントの両方からrequireし易いように、routesの中身だけ切り出す。
    • Routerroutesに渡してやればClientはOK。

サーバーサイドで描画!

  • サーバーサイドでは、ReactのroutesとURLのパスをreact-routermatchに渡してやる。
    • RouterContextRouterが描画するときに使うもの。というかこれをそのまま返している。
    • Routerは描画にbrowserHistoryを使うけど、サーバーはステートレスなのでmatchでhistoryをpropsに詰めて渡している。
  • 整理すると:
    • 描画自体はRouterContextが行っている。
    • そのためにbrowserHistoryの情報が必要。
    • browserHistoryの生成をmatchが担当している。
    • という理解で良いのかな。

ハマったところ

staticなfileのディレクトリを指定するところ、オプションに{index:false}入れておかないとCSSやJSが配信されなくて毎回HTTPリクエストが走ってしまった。

app.use(express.static(__dirname + '/public'), {index: false})        

おわり

前回に引き続きreact-routerチュートリアルを済ませた。大体理解したので、また何か作ってみたいなあという雰囲気。あとはReduxとかやればいいかなあ。