今回はComponentについて書いていきたいと思います。
React.jsでは基本的にはComponentを作って組み合わせていくことでアプリケーションを作っていきます。
render
ComponentはReact.createClass
にrender
メソッドをもったオブジェクトを渡すことで作成することが出来ます。
var Hello = React.createClass({
render() {
return (
<div><span>hello</span></div>
)
}
})
その際、render
メソッドはComponentを1つ返す必要があります。
↓のように複数のComponentを返すことは出来ません。
// ダメ
render() {
return (
<div>title</div>
<div>contents</div>
)
}
// OK
render() {
return (
<div>
<div>title</div>
<div>contents</div>
</div>
)
}
また、renderメソッドはどのタイミングで何度呼ばれるかわからないので必ず冪等性がある実装にする必要があります。
Separation of concerns?
ところで、React.jsではComponentとして、マークアップとViewのロジックをcreateClassの中に書いていくのですが、他のフレームワークのようにマークアップはHTMLやmustacheで書いてViewのロジックをJSで書くみたいに分かれてなくて気持ち悪い!という人もいるのではないでしょうか?
それに対して、React.jsの開発者であるPete Huntはそれは「関心の分離(Separation of concerns)」ではなくて「技術の分離(Separation of technologies)」だとしていて、マークアップとViewのロジックは密であるべきとしています。
それにTemplateのSyntaxで不自由にコードを書くよりJavaScriptで書いた方がいいとしています。
テストが...という問題は、React.jsではTestUtilsというAddonでサポートしています。
Component間のやりとり
PropをI/Fとして外部とやりとりすることが出来ます。
<Hello name="foo" />
のようにすると、this.props.name
として参照することが出来ます。
var Hello = React.createClass({
render() {
return (
<div>Hello {this.props.name}</div>
)
}
});
// <Hello name="React" />
// <div>Hello React</div>
Propについては明日に書く予定です。
動的に更新する
ユーザーのアクションやAjaxリクエストなどにより、動的に値が変化するような場合はStateを使います。
this.state.xxx
で参照して、更新するときはthis.state
を更新するのではなくて必ずthis.setState
を使用する必要があります。
var Counter = React.createClass({
getInitialState() {
return {
count: 0
};
},
onClick() {
this.setState({count: this.state.count + 1});
},
render() {
return (
<div>
<div>count:{this.state.count}</div>
<button onClick={this.onClick}>click!</button>
</div>
);
}
});
Stateについては明後日に書く予定です。
React.createClassについて
Componentを作成にするときに使う関数ですが、v0.11からv0.12にかけて挙動が変わりました。
以前は、Componentの定義を作りつつComponentのElementを返しているという2つのことをやっていたのですが、v0.12からはそれが分離されてComponentの定義を作成して返すだけになりました。
つまりElementではないので、使うときにはReact.createElement(Component, {name: 'xxx'})
のようにReact Elementにしてあげる必要があります。ちなみにReact.createFactory(Component)
とやることも出来ます。
ただJSXを使っている場合は、これまでと同じようにReact.createClass
の戻り値を<Component />
のように直接渡しても大丈夫です。
var Hello = React.createClass({
render() {
return <div>{this.props.name}</div>;
}
});
React.render(React.createElement(Hello, {name: "foo"}), document.body);
// or
React.render(React.createFactory(Hello)({name: "foo"}), document.body);
// JSXはそのままでOK
React.render(<Hello name="foo" />, document.body);
この変更には今までがcreateClassという名前以上のことをやっていたというのもあるのですが、createElementを通してComponentを作成するようにすることで最適化の余地を与えたり、将来的にReact.createClass
を使っているところをES6のclassで定義出来るようにするという意図もあったりします。
Componentについてはそのほかにも、Lifecycleに応じたhookがあったりするのですが、その辺りについても今後紹介していきたいと思います。
明日はProp
について書きたいと思います。