-
react-router v2.xとcontext
- 2016年2月25日
- React
- react-router
※この記事は
http://qiita.com/kuniken/items/b8777c8342fe1b4ff727
で投稿した内容と同じものです。
react-router また仕様変更
react-router v1.xからv2.xへのバージョンアップ
v0.xからv1.xにあがった時点で色々ありましたが、v2.xでもまた色々あるみたいです。 本家サイトに、v2.0.0 Upgrade Guideがありました。 それによると、大きな変更点は、- historyをrouter定義時に必ず指定することになった
- コンポーネント定義時にmixinsでHistoryを指定しなくなった
- contextでrouterを使い回すことになった
- なのでpushStateなんかはcontext.router.push()とかすることになった
- 今までの実装のままだとコンソールに警告出る、で、次のVerから使えなくなる
context
以前はReactの公式ページでは確かcontextについて記述がなかったのですが、いつの頃からか記述が追加されました。 https://facebook.github.io/react/docs/context.html githubの履歴を調べたら最初のコミットが2015年10月10日になっていました。 公式な記述が追加されたってことは、条件付きだったとしても使っていいよ、ってことですよね。contextの便利なところ
contextを使わない場合、親から子に値を渡す時は、以下のように、var Parent = React.createClass({
:
:
render: function(){
return (
<Child param={this.state.param} />
);
}
});
var Child = React.createClass({
render: function(){
return (
<div>{this.props.param}</div>
);
}
});
stateとpropsを使って、受け渡しをする必要がありました。
これをcontextに置き換えた場合、子供に値を渡してあげる必要がありません。
var Parent = React.createClass({
getChildContext: function() {
return {param: ''};
},
:
:
render: function(){
return (
<Child /> {/* contextの場合、値を渡す必要なし */}
);
}
});
var Child = React.createClass({
render: function(){
return (
<div>{this.context.param}</div> {/* contextの値を参照 */}
);
}
});
多用しないでね。
公式ページには注意書きがあります。適当に訳してみました。Note: contextは、先進的かつ実験的な機能です。APIは、将来のリリースで変更する可能性があります。 ほとんどのアプリでは、contextを使用する必要はありません。あなたがReact.jsを使い始めの場合は特に必要ないでしょう。contextを使用すると、データの流れが不明瞭になりますので、コードを理解するのが難しくなります。あなたのアプリでcontextを使うということは、グローバル変数としてstateを受け渡すのと同様のことなのです。 contextを使用する必要がある場合、慎重に行ってください アプリを実装するかライブラリを実装するかによらず、contextの使用は小さな領域に分離し、直接APIを触らないように実装してみてください。それができれば、APIが変更されてもアップグレード作業がより簡単にできます。とのことです。おかしかったらコメントください。 redux使ってたらあんまり使うことはなさそうな気もします。
react-router v1.xベースのソースをv2.xベースに修正してみる
今日から始めるシリーズで使ってるソースを使って、v2.xベースに修正してみます。npm インストール
npmを最新にして、react-router、historyを2.0.0にしました。$ sudo npm install npm -g
$ npm install react-router@2.0.0 history@2.0.0 --save
出るか警告
でました。いざ修正
1個目の警告は、これのせいですね。公式サイトだと、 No Default History Using Browser (HTML5 pushState) History Using Custom Histories に詳しい記述があります。 ということで、historyをインポートします。で、Routerに渡してあげます。
- historyをrouter定義時に必ず指定することになった
//index.js
var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var hashHistory = ReactRouter.hashHistory;
//browserHistoryの場合
//var browserHistory = ReactRouter.browserHistory;
:
ReactDOM.render(
<Router history={hashHistory}>{Routes}</Router>,
document.getElementById('content')
);
次に、2個目以降の警告の部分、
について修正します。もともとのソースは、
- コンポーネント定義時にmixinsでHistoryを指定しなくなった
- contextでrouterを使い回すことになった
- なのでpushStateなんかはcontext.router.push()とかすることになった
//index.js
var Top = React.createClass({
mixins: [ History ],
handleSubmit:function(e){
e.preventDefault();
/* ログイン処理 */
//ポータルページへ
this.history.pushState(null, '/portal');
},
render:function(){
return (
<div>
<div className="main">
<h1>ログイン</h1>
<form onSubmit={this.handleSubmit}>
<input placeholder="userid"/>
<input placeholder="password"/>
<div style={{textAlign:"center"}}>
<button type="submit">ログイン</button>
</div>
</form>
</div>
</div>
);
}
});
こんな感じでした。
ので、
- contextの定義。
- mixins: [History]を削除。
- this.history.pushState(null, ‘/portal’);の修正。
//index.js
var Top = React.createClass({
contextTypes: {
router: React.PropTypes.object.isRequired
},
handleSubmit:function(e){
e.preventDefault();
/* ログイン処理 */
//ポータルページへ
this.context.router.push('/portal'); //!!
},
render:function(){
return (
<div>
<div className="main">
<h1>ログイン</h1>
<form onSubmit={this.handleSubmit}>
<input placeholder="userid"/>
<input placeholder="password"/>
<div style={{textAlign:"center"}}>
<button type="submit">ログイン</button>
</div>
</form>
</div>
</div>
);
}
});
上記の修正の、
this.context.router.push('/portal');
についてですが、pushState、replaceStateといった〜State()は、公式サイトの、
Programmatic Navigation
にあるように、引数も変更されています。
path以外でqueryとかを指定したい場合は、オブジェクトで渡す必要があります。
this.context.router.push({pathname: '/portal', query: '', state: ''});
引数の変更についてはLinkコンポーネントでも同様です。
公式サイトの、
\, onEnter, and isActive use location descriptors
によると、query付きで渡したい場合は、
//V1.x
<Link to="/portal" query={{q: "hoge"}} style={{paddingRight: "5px"}}>ポータル</Link>
が、
//V2.x
<Link to={{pathname: "/portal", query: {q: "hoge"}}} style={{paddingRight: "5px"}}>ポータル</Link>
になります。
んー
contextが変更する可能性があるというなら、結局自分でmixinを作ったりとかラッパーを作ったりしないといけなくなるのではなかろうか。
移行ツール
公式サイトでは、移行ツールを使った修正方法について案内があります。 Upgrade Automatically with Codemods それによると、 https://github.com/rackt/rackt-codemod に書いてある方法でインストールし、ツールを動かしてと書いてあります。$ sudo npm install -g jscodeshift
$ npm install rackt-codemod
ツールを動かしてみます。以下な感じ。
$ jscodeshift -t node_modules/rackt-codemod/transforms/history/deprecate-pushState-replaceState.js ./client/scripts/*
結果を見たら、
Processing 5 files...
Spawning 1 workers with 5 files each...
All done.
Results: 0 errors 4 unmodified 0 skipped 1 ok
Time elapsed: 1.99 seconds
とでました。1ファイルpushStateがpushに修正されました。多階層には対応しているのだろうか。。
また、react-router/deprecate-context-history.jsも実行してみましたが、
mixinsはそのままでした。関係ないのかな。
サンプルソース
https://github.com/kunitak/react-router-1to2/tree/v2この記事を書いた人 : 國田健史
スタッフブログタグ:
AWS bluebird css CSV docker docker compose electron ES6 es2015 Git Heroku ITコンサルティング JavaScript justinmind less mongoDB Node.js php PostgreSQL Private Space Promise React react-router reactjs Salesforce scss Selenium Builder selenium IDE Selenium WebDriver stylus TypeScript VirtualBox VisualStudioCode vue vuejs webpack システム開発プロジェクト セキュリティ ワイヤーフレーム 上流工程 卒FIT 帳票 要件定義 設計 電力小売業界
一覧へ戻る
AWS bluebird css CSV docker docker compose electron ES6 es2015 Git Heroku ITコンサルティング JavaScript justinmind less mongoDB Node.js php PostgreSQL Private Space Promise React react-router reactjs Salesforce scss Selenium Builder selenium IDE Selenium WebDriver stylus TypeScript VirtualBox VisualStudioCode vue vuejs webpack システム開発プロジェクト セキュリティ ワイヤーフレーム 上流工程 卒FIT 帳票 要件定義 設計 電力小売業界