React.jsに触れてみる3 (2の修正)
前回をなんとなくChromeで表示したところ、エラーが結構出ていたため修正したお話。
ソースコード
javascript.js
(function () { var _intRightTabNum = 2; // 動的にCSSを切り替えるのに使用. var tabBgStyle = { color: '#0000FF' }; var ShowTabs = React.createClass({ getInitialState: function() { return{ allowColor: tabBgStyle, innerTabs: [{btnId: 'btn_0', lblId: 'btn_label_0', text: 'Tab1'} , {btnId: 'btn_1', lblId: 'btn_label_1', text: 'Tab2'}] }; }, getDefaultProps: function() { // デフォルトで表示するコンテンツ return { content: < div id='page_contents' >Hello< /div > }; }, moveTab: function(event){ switch (event.target.id){ case 'arrow_button_left': // 一つ左隣のTabを表示. _intRightTabNum--; console.log("left"); break; case 'arrow_button_right': // 一つ右隣のTabを表示. _intRightTabNum++; console.log("right"); break; } }, movePage: function (event) { switch(event.target.id) { case 'tab_0': // StateとしてセットしているinnerTabsの要素数分ShowInnerTabsを取得する. var innerTabs = this.state.innerTabs.map(function(innerTab) { return (< ShowInnerTabs onClick={this.changeColor} innerTab={innerTab} / >); }.bind(this)); this.setProps({content: < div id='page_contents' > < section id='btn_frame' > {innerTabs} < /section > < /div >}); break; case 'tab_1': this.setProps({content: < div id='page_contents' >Hello< /div >}); break; } }, changeColor: function(strBtnId) { switch(strBtnId) { case 'btn_0': tabBgStyle.color = '#00FF00'; break; case 'btn_1': tabBgStyle.color = '#FF0000'; break; } this.setState({allowColor: tabBgStyle}); }, render: function() { return ( < section id='tab_frame' > < input id='arrow_button_left' className='button_arrow' type='button' onClick={this.moveTab} / > < label className='arrow_label' htmlFor='arrow_button_left' style={this.state.allowColor} ><< /label > < input id='tab_0' className='tab_radio' type='radio' name='tabs' onChange={this.movePage} / > < label className='tab_label' htmlFor='tab_0' >タブ1< /label > < input id='tab_1' className='tab_radio' type='radio' name='tabs' onChange={this.movePage} / > < label id='tab_label_1' className='tab_label' htmlFor='tab_1' >タブ2< /label > < input id='arrow_button_right' className='button_arrow' type='button' onClick={this.moveTab} / > < label className='arrow_label' htmlFor='arrow_button_right' >>< /label > {this.props.content} < /section > ); } }); // ShowTabsの子として呼ばれ、コンテンツの中身を表示する. var ShowInnerTabs = React.createClass({ propTypes: { // 親から受け取るpropsのデータ型を指定する. btnId: React.PropTypes.string.isRequired, lblId: React.PropTypes.string.isRequired, text: React.PropTypes.string.isRequired, onClick: React.PropTypes.func.isRequired }, render: function() { return ( < input id={this.props.innerTab.btnId} type='radio' name='btns' onClick={this.props.onClick} > < label id={this.props.innerTab.lblId} className='btn_label' htmlFor={this.props.innerTab.btnId} > {this.props.innerTab.text} < /label > < /input > ); } }); React.render(< ShowTabs/ >, document.getElementById('main')); }).call(this);
関数名() -> 関数名: function()に変更
ShowTabsのgetInitialState()などを、「getInitialState: function()」に変更しました。
map関数の変更
正直コレに時間がかかりました...。
「var innerTabs = this.state.innerTabs.map((innerTab) => {」を、 「var innerTabs = this.state.innerTabs.map(function(innerTab){」に変更すると、「=>」で発生していたSyntaxErrorは解消します。
しかし、実際にコードを実行してみると、生成したコード内のonClickで、「this.props.onClick is not a function」というエラーが発生。
結局、「.bind(this)」をつけて関数を生成するようにしてやると解決しました。
ちなみにmap、bindともにReact固有の関数ではなく、Javascript自身が持っているため、Reactを使わない時でも利用すると便利かもしれません。
var innerTabs = this.state.innerTabs.map(function(innerTab) { return (< ShowInnerTabs onClick={this.changeColor} innerTab={innerTab} / >); }.bind(this));
ついでに、クリックしたタブ番号を取得するために使用していたtabNumは、btnIdなど固有で持たせている値があるので不要と感じたため削除しています。
というわけで、FirefoxとChromeではエラー無しで表示・実行できるようになりました。
モバイル環境などではちゃんと動くのか...。そろそろサーバー上で実行できるようにしたいところです
(といっても、Sinatra + Webrickであればすぐ動かせちゃいますが)。